icdev 1.0.0__py3-none-any.whl
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.
- icdev/__init__.py +18 -0
- icdev/_paths.py +85 -0
- icdev/_version.py +3 -0
- icdev/data/__init__.py +1 -0
- icdev/data/args/__init__.py +1 -0
- icdev/data/args/agent_authority.yaml +61 -0
- icdev/data/args/agent_config.yaml +355 -0
- icdev/data/args/agentic_fitness.yaml +31 -0
- icdev/data/args/ai_governance_config.yaml +137 -0
- icdev/data/args/atlas_critique_config.yaml +66 -0
- icdev/data/args/bedrock_models.yaml +63 -0
- icdev/data/args/cicd_config.yaml +82 -0
- icdev/data/args/classification_config.yaml +232 -0
- icdev/data/args/cli_config.yaml +154 -0
- icdev/data/args/cloud_config.yaml +63 -0
- icdev/data/args/code_pattern_config.yaml +151 -0
- icdev/data/args/code_quality_config.yaml +47 -0
- icdev/data/args/companion_registry.yaml +202 -0
- icdev/data/args/context_config.yaml +82 -0
- icdev/data/args/csp_monitor_config.yaml +268 -0
- icdev/data/args/cui_markings.yaml +35 -0
- icdev/data/args/db_config.yaml +40 -0
- icdev/data/args/deployment_profiles.yaml +248 -0
- icdev/data/args/dev_profile_config.yaml +144 -0
- icdev/data/args/devsecops_config.yaml +286 -0
- icdev/data/args/endpoint_security_config.yaml +137 -0
- icdev/data/args/extension_config.yaml +79 -0
- icdev/data/args/file_access_tiers.yaml +88 -0
- icdev/data/args/framework_registry.yaml +415 -0
- icdev/data/args/innovation_config.yaml +431 -0
- icdev/data/args/installation_manifest.yaml +1087 -0
- icdev/data/args/llm_config.yaml +495 -0
- icdev/data/args/maintenance_config.yaml +55 -0
- icdev/data/args/memory_config.yaml +83 -0
- icdev/data/args/monitoring_config.yaml +127 -0
- icdev/data/args/mosa_config.yaml +190 -0
- icdev/data/args/nlq_config.yaml +35 -0
- icdev/data/args/observability_config.yaml +39 -0
- icdev/data/args/observability_tracing_config.yaml +170 -0
- icdev/data/args/oscal_tools_config.yaml +43 -0
- icdev/data/args/owasp_agentic_config.yaml +171 -0
- icdev/data/args/phase_registry.yaml +618 -0
- icdev/data/args/project_defaults.yaml +235 -0
- icdev/data/args/prompt_chains.yaml +163 -0
- icdev/data/args/resilience_config.yaml +50 -0
- icdev/data/args/ricoas_config.yaml +191 -0
- icdev/data/args/role_personas.yaml +362 -0
- icdev/data/args/scaling_config.yaml +176 -0
- icdev/data/args/security_gates.yaml +685 -0
- icdev/data/args/skill_injection_config.yaml +322 -0
- icdev/data/args/spec_config.yaml +53 -0
- icdev/data/args/supply_chain_config.yaml +76 -0
- icdev/data/args/translation_config.yaml +228 -0
- icdev/data/args/workflow_templates/ato_acceleration.yaml +54 -0
- icdev/data/args/workflow_templates/build_deploy.yaml +63 -0
- icdev/data/args/workflow_templates/full_compliance.yaml +43 -0
- icdev/data/args/workflow_templates/security_hardening.yaml +55 -0
- icdev/data/args/worktree_config.yaml +34 -0
- icdev/data/args/zta_config.yaml +247 -0
- icdev/data/context/__init__.py +1 -0
- icdev/data/context/agent/__init__.py +1 -0
- icdev/data/context/agent/response_schemas/__init__.py +1 -0
- icdev/data/context/agent/response_schemas/debate_position.json +46 -0
- icdev/data/context/agent/response_schemas/fitness_scorecard.json +74 -0
- icdev/data/context/agent/response_schemas/review_decision.json +39 -0
- icdev/data/context/agent/response_schemas/task_decomposition.json +82 -0
- icdev/data/context/agent/response_schemas/veto_decision.json +40 -0
- icdev/data/context/agentic/__init__.py +1 -0
- icdev/data/context/agentic/architecture_patterns.md +269 -0
- icdev/data/context/agentic/capability_registry.yaml +202 -0
- icdev/data/context/agentic/csp_mcp_registry.yaml +280 -0
- icdev/data/context/agentic/fitness_rubric.md +56 -0
- icdev/data/context/agentic/governance_baseline.md +205 -0
- icdev/data/context/ci/__init__.py +1 -0
- icdev/data/context/ci/worktree_templates.json +44 -0
- icdev/data/context/cloud/__init__.py +1 -0
- icdev/data/context/cloud/csp_service_registry.json +739 -0
- icdev/data/context/compliance/__init__.py +1 -0
- icdev/data/context/compliance/atlas_mitigations.json +293 -0
- icdev/data/context/compliance/atlas_techniques.json +833 -0
- icdev/data/context/compliance/cisa_sbd_requirements.json +432 -0
- icdev/data/context/compliance/cjis_security_policy.json +522 -0
- icdev/data/context/compliance/cmmc_practices.json +2494 -0
- icdev/data/context/compliance/cmmc_report_template.md +142 -0
- icdev/data/context/compliance/cnssi_1253_overlay.json +109 -0
- icdev/data/context/compliance/control_crosswalk.json +1914 -0
- icdev/data/context/compliance/control_families/__init__.py +1 -0
- icdev/data/context/compliance/csp_certifications.json +251 -0
- icdev/data/context/compliance/cssp_report_template.md +193 -0
- icdev/data/context/compliance/cui_templates/__init__.py +1 -0
- icdev/data/context/compliance/cui_templates/banner_block.txt +4 -0
- icdev/data/context/compliance/cui_templates/code_header.txt +8 -0
- icdev/data/context/compliance/cui_templates/document_template.md +35 -0
- icdev/data/context/compliance/data_type_framework_map.json +321 -0
- icdev/data/context/compliance/data_type_registry.json +147 -0
- icdev/data/context/compliance/dod_cssp_8530.json +463 -0
- icdev/data/context/compliance/eu_ai_act_annex_iii.json +108 -0
- icdev/data/context/compliance/export_templates/__init__.py +1 -0
- icdev/data/context/compliance/export_templates/emass_controls.csv.j2 +4 -0
- icdev/data/context/compliance/export_templates/evidence_package.md.j2 +39 -0
- icdev/data/context/compliance/export_templates/executive_summary.md.j2 +55 -0
- icdev/data/context/compliance/export_templates/poam_tracking.csv.j2 +4 -0
- icdev/data/context/compliance/fedramp_20x_ksi_schemas.json +133 -0
- icdev/data/context/compliance/fedramp_high_baseline.json +4370 -0
- icdev/data/context/compliance/fedramp_moderate_baseline.json +2183 -0
- icdev/data/context/compliance/fedramp_report_template.md +181 -0
- icdev/data/context/compliance/fips_200_areas.json +362 -0
- icdev/data/context/compliance/gao_ai_accountability.json +262 -0
- icdev/data/context/compliance/hipaa_security_rule.json +720 -0
- icdev/data/context/compliance/hitrust_csf_v11.json +930 -0
- icdev/data/context/compliance/impact_level_profiles.json +251 -0
- icdev/data/context/compliance/incident_response_template.md +1110 -0
- icdev/data/context/compliance/iso27001_2022_controls.json +750 -0
- icdev/data/context/compliance/iso27001_nist_bridge.json +382 -0
- icdev/data/context/compliance/iso42001_controls.json +254 -0
- icdev/data/context/compliance/ivv_checklist_template.md +80 -0
- icdev/data/context/compliance/ivv_report_template.md +116 -0
- icdev/data/context/compliance/ivv_requirements.json +372 -0
- icdev/data/context/compliance/mosa_crosswalk.json +327 -0
- icdev/data/context/compliance/mosa_framework.json +250 -0
- icdev/data/context/compliance/narrative_templates/AC.md.j2 +101 -0
- icdev/data/context/compliance/narrative_templates/AU.md.j2 +106 -0
- icdev/data/context/compliance/narrative_templates/IA.md.j2 +104 -0
- icdev/data/context/compliance/narrative_templates/SC.md.j2 +102 -0
- icdev/data/context/compliance/narrative_templates/SI.md.j2 +111 -0
- icdev/data/context/compliance/narrative_templates/__init__.py +1 -0
- icdev/data/context/compliance/narrative_templates/default.md.j2 +50 -0
- icdev/data/context/compliance/narrative_templates/executive_summary.j2 +27 -0
- icdev/data/context/compliance/narrative_templates/poam_milestone.j2 +19 -0
- icdev/data/context/compliance/narrative_templates/ssp_section.j2 +11 -0
- icdev/data/context/compliance/nist_800_171_controls.json +1552 -0
- icdev/data/context/compliance/nist_800_207_crosswalk.json +399 -0
- icdev/data/context/compliance/nist_800_207_zta.json +258 -0
- icdev/data/context/compliance/nist_800_53.json +324 -0
- icdev/data/context/compliance/nist_ai_600_1_genai.json +326 -0
- icdev/data/context/compliance/nist_ai_rmf.json +206 -0
- icdev/data/context/compliance/nist_sp_800_60_types.json +1667 -0
- icdev/data/context/compliance/omb_m25_21_high_impact_ai.json +248 -0
- icdev/data/context/compliance/omb_m26_04_unbiased_ai.json +262 -0
- icdev/data/context/compliance/owasp_agentic_asi.json +133 -0
- icdev/data/context/compliance/owasp_agentic_threats.json +285 -0
- icdev/data/context/compliance/owasp_llm_top10.json +274 -0
- icdev/data/context/compliance/pci_dss_v4.json +510 -0
- icdev/data/context/compliance/poam_template.md +117 -0
- icdev/data/context/compliance/safeai_controls.json +512 -0
- icdev/data/context/compliance/sbd_report_template.md +77 -0
- icdev/data/context/compliance/siem_config_templates/__init__.py +1 -0
- icdev/data/context/compliance/siem_config_templates/filebeat.yml +213 -0
- icdev/data/context/compliance/siem_config_templates/log_sources.json +208 -0
- icdev/data/context/compliance/soc2_trust_criteria.json +661 -0
- icdev/data/context/compliance/ssp_template.md +432 -0
- icdev/data/context/compliance/stig_templates/__init__.py +1 -0
- icdev/data/context/compliance/stig_templates/webapp_stig.json +139 -0
- icdev/data/context/compliance/xai_requirements.json +108 -0
- icdev/data/context/dashboard/__init__.py +1 -0
- icdev/data/context/dashboard/nlq_examples.json +50 -0
- icdev/data/context/dashboard/schema_descriptions.json +23 -0
- icdev/data/context/integration/__init__.py +1 -0
- icdev/data/context/integration/approval_workflows.json +32 -0
- icdev/data/context/integration/gitlab_field_mappings.json +33 -0
- icdev/data/context/integration/jira_field_mappings.json +32 -0
- icdev/data/context/integration/reqif_export_schema.json +23 -0
- icdev/data/context/integration/servicenow_field_mappings.json +22 -0
- icdev/data/context/languages/__init__.py +1 -0
- icdev/data/context/languages/framework_patterns.json +205 -0
- icdev/data/context/languages/language_registry.json +279 -0
- icdev/data/context/llm/__init__.py +1 -0
- icdev/data/context/llm/example_provider.py +86 -0
- icdev/data/context/mbse/__init__.py +1 -0
- icdev/data/context/mbse/des_report_template.md +162 -0
- icdev/data/context/mbse/des_requirements.json +411 -0
- icdev/data/context/mbse/digital_thread_patterns.json +403 -0
- icdev/data/context/mbse/reqif_schema.json +280 -0
- icdev/data/context/mbse/sysml_element_types.json +432 -0
- icdev/data/context/modernization/__init__.py +1 -0
- icdev/data/context/modernization/db_type_mappings.json +148 -0
- icdev/data/context/modernization/decomposition_patterns.json +284 -0
- icdev/data/context/modernization/framework_migration_patterns.json +359 -0
- icdev/data/context/modernization/migration_report_template.md +168 -0
- icdev/data/context/modernization/seven_rs_catalog.json +369 -0
- icdev/data/context/modernization/version_upgrade_rules.json +279 -0
- icdev/data/context/oscal/NIST_SP-800-53_rev5_catalog.json +254987 -0
- icdev/data/context/oscal/README.md +43 -0
- icdev/data/context/patterns/__init__.py +1 -0
- icdev/data/context/profiles/__init__.py +1 -0
- icdev/data/context/profiles/dod_baseline_v1.yaml +145 -0
- icdev/data/context/profiles/fedramp_baseline_v1.yaml +143 -0
- icdev/data/context/profiles/financial_baseline_v1.yaml +142 -0
- icdev/data/context/profiles/healthcare_baseline_v1.yaml +135 -0
- icdev/data/context/profiles/law_enforcement_v1.yaml +129 -0
- icdev/data/context/profiles/startup_v1.yaml +134 -0
- icdev/data/context/requirements/__init__.py +1 -0
- icdev/data/context/requirements/ambiguity_patterns.json +97 -0
- icdev/data/context/requirements/boundary_impact_rules.json +123 -0
- icdev/data/context/requirements/default_constitutions.json +67 -0
- icdev/data/context/requirements/document_extraction_rules.json +58 -0
- icdev/data/context/requirements/gap_patterns.json +108 -0
- icdev/data/context/requirements/readiness_rubric.json +78 -0
- icdev/data/context/requirements/red_alternative_patterns.json +210 -0
- icdev/data/context/requirements/safe_templates.json +72 -0
- icdev/data/context/requirements/spec_quality_checklist.json +122 -0
- icdev/data/context/simulation/__init__.py +1 -0
- icdev/data/context/simulation/architecture_patterns.json +36 -0
- icdev/data/context/simulation/coa_templates.json +38 -0
- icdev/data/context/simulation/cost_models.json +23 -0
- icdev/data/context/simulation/risk_categories.json +46 -0
- icdev/data/context/supply_chain/__init__.py +1 -0
- icdev/data/context/supply_chain/isa_templates.json +129 -0
- icdev/data/context/supply_chain/nist_800_161_controls.json +247 -0
- icdev/data/context/supply_chain/scrm_risk_matrix.json +147 -0
- icdev/data/context/templates/__init__.py +1 -0
- icdev/data/context/templates/ansible/__init__.py +1 -0
- icdev/data/context/templates/ansible/playbooks/__init__.py +1 -0
- icdev/data/context/templates/ansible/roles/__init__.py +1 -0
- icdev/data/context/templates/gitlab_ci/__init__.py +1 -0
- icdev/data/context/templates/grafana/__init__.py +1 -0
- icdev/data/context/templates/kubernetes/__init__.py +1 -0
- icdev/data/context/templates/project/__init__.py +1 -0
- icdev/data/context/templates/project/api/__init__.py +1 -0
- icdev/data/context/templates/project/cli/__init__.py +1 -0
- icdev/data/context/templates/project/data_pipeline/__init__.py +1 -0
- icdev/data/context/templates/project/iac/__init__.py +1 -0
- icdev/data/context/templates/project/javascript_frontend/__init__.py +1 -0
- icdev/data/context/templates/project/javascript_frontend/src/__init__.py +1 -0
- icdev/data/context/templates/project/javascript_frontend/tests/__init__.py +1 -0
- icdev/data/context/templates/project/microservice/__init__.py +1 -0
- icdev/data/context/templates/project/python_backend/__init__.py +1 -0
- icdev/data/context/templates/project/python_backend/src/__init__.py +1 -0
- icdev/data/context/templates/project/python_backend/tests/__init__.py +1 -0
- icdev/data/context/templates/project/python_backend/tests/features/__init__.py +1 -0
- icdev/data/context/templates/project/python_backend/tests/steps/__init__.py +1 -0
- icdev/data/context/templates/terraform/__init__.py +1 -0
- icdev/data/context/templates/terraform/govcloud_base/__init__.py +1 -0
- icdev/data/context/templates/terraform/modules/__init__.py +1 -0
- icdev/data/context/tone/__init__.py +1 -0
- icdev/data/context/translation/dependency_mappings.json +186 -0
- icdev/data/context/translation/type_mappings.json +149 -0
- icdev/data/docs/README.md +187 -0
- icdev/data/docs/__init__.py +1 -0
- icdev/data/docs/admin/gateway-guide.md +338 -0
- icdev/data/docs/admin/marketplace-guide.md +396 -0
- icdev/data/docs/admin/monitoring-guide.md +509 -0
- icdev/data/docs/architecture/compliance-framework.md +764 -0
- icdev/data/docs/architecture/database-schema.md +689 -0
- icdev/data/docs/architecture/gotcha-framework.md +518 -0
- icdev/data/docs/architecture/multi-agent-system.md +603 -0
- icdev/data/docs/dx/README.md +106 -0
- icdev/data/docs/dx/__init__.py +1 -0
- icdev/data/docs/dx/ci-cd-integration.md +378 -0
- icdev/data/docs/dx/claude-code-guide.md +213 -0
- icdev/data/docs/dx/companion-guide.md +232 -0
- icdev/data/docs/dx/dev-profiles.md +309 -0
- icdev/data/docs/dx/icdev-yaml-spec.md +219 -0
- icdev/data/docs/dx/integration-tiers.md +279 -0
- icdev/data/docs/dx/llm-routing-guide.md +456 -0
- icdev/data/docs/dx/quickstart.md +192 -0
- icdev/data/docs/dx/sdk-reference.md +356 -0
- icdev/data/docs/dx/unified-mcp-setup.md +525 -0
- icdev/data/docs/features/__init__.py +1 -0
- icdev/data/docs/features/phase-01-gotcha-framework.md +249 -0
- icdev/data/docs/features/phase-02-atlas-build-workflow.md +223 -0
- icdev/data/docs/features/phase-03-tdd-bdd-testing.md +261 -0
- icdev/data/docs/features/phase-04-nist-compliance.md +255 -0
- icdev/data/docs/features/phase-05-security-scanning.md +229 -0
- icdev/data/docs/features/phase-06-infrastructure-deployment.md +288 -0
- icdev/data/docs/features/phase-07-code-review-gates.md +276 -0
- icdev/data/docs/features/phase-08-self-healing.md +223 -0
- icdev/data/docs/features/phase-09-monitoring-observability.md +230 -0
- icdev/data/docs/features/phase-10-dashboard-web-ui.md +218 -0
- icdev/data/docs/features/phase-11-multi-agent-architecture.md +272 -0
- icdev/data/docs/features/phase-12-integration-testing.md +228 -0
- icdev/data/docs/features/phase-13-cicd-integration.md +257 -0
- icdev/data/docs/features/phase-14-secure-by-design-ivv.md +240 -0
- icdev/data/docs/features/phase-15-maintenance-audit.md +192 -0
- icdev/data/docs/features/phase-16-ato-acceleration.md +228 -0
- icdev/data/docs/features/phase-17-multi-framework-compliance.md +223 -0
- icdev/data/docs/features/phase-18-mbse-integration.md +242 -0
- icdev/data/docs/features/phase-19-agentic-generation.md +202 -0
- icdev/data/docs/features/phase-20-fips-security-categorization.md +198 -0
- icdev/data/docs/features/phase-21-saas-multi-tenancy.md +273 -0
- icdev/data/docs/features/phase-22-federated-gotcha-marketplace.md +242 -0
- icdev/data/docs/features/phase-23-universal-compliance-platform.md +238 -0
- icdev/data/docs/features/phase-24-devsecops-pipeline-security.md +198 -0
- icdev/data/docs/features/phase-25-zero-trust-architecture.md +220 -0
- icdev/data/docs/features/phase-26-dod-mosa.md +205 -0
- icdev/data/docs/features/phase-27-cli-capabilities.md +222 -0
- icdev/data/docs/features/phase-28-remote-command-gateway.md +235 -0
- icdev/data/docs/features/phase-29-proactive-monitoring.md +212 -0
- icdev/data/docs/features/phase-30-dashboard-auth.md +215 -0
- icdev/data/docs/features/phase-31-dashboard-ux-low-impact.md +188 -0
- icdev/data/docs/features/phase-32-dashboard-ux-medium-impact.md +223 -0
- icdev/data/docs/features/phase-33-modular-installation.md +218 -0
- icdev/data/docs/features/phase-34-dev-profiles.md +239 -0
- icdev/data/docs/features/phase-35-innovation-engine.md +257 -0
- icdev/data/docs/features/phase-36-evolutionary-intelligence.md +351 -0
- icdev/data/docs/features/phase-37-mitre-atlas-integration.md +485 -0
- icdev/data/docs/features/phase-38-cloud-agnostic-architecture.md +1033 -0
- icdev/data/docs/features/phase-39-observability-operations.md +178 -0
- icdev/data/docs/features/phase-40-nlq-compliance-queries.md +176 -0
- icdev/data/docs/features/phase-41-parallel-cicd.md +169 -0
- icdev/data/docs/features/phase-42-framework-planning.md +177 -0
- icdev/data/docs/features/phase-43-cross-language-translation.md +225 -0
- icdev/data/docs/features/phase-44-innovation-adaptation.md +227 -0
- icdev/data/docs/features/phase-45-owasp-agentic-security.md +239 -0
- icdev/data/docs/features/phase-46-observability-traceability-xai.md +240 -0
- icdev/data/docs/features/phase-47-unified-mcp-gateway.md +257 -0
- icdev/data/docs/features/phase-48-ai-transparency.md +203 -0
- icdev/data/docs/features/phase-49-ai-accountability.md +243 -0
- icdev/data/docs/features/phase-50-ai-governance-intake-chat.md +195 -0
- icdev/data/docs/features/phase-51-unified-chat-dashboard.md +240 -0
- icdev/data/docs/features/phase-52-code-intelligence.md +244 -0
- icdev/data/docs/features/phase-53-fedramp-20x-owasp-asi.md +359 -0
- icdev/data/docs/features/phase-54-slsa-swft-orchestration.md +379 -0
- icdev/data/docs/features/phase-55-a2a-v03-mcp-oauth.md +322 -0
- icdev/data/docs/features/phase-56-evidence-lineage.md +352 -0
- icdev/data/docs/features/phase-57-eu-ai-act-iron-bank.md +319 -0
- icdev/data/docs/features/phase-58-creative-engine.md +370 -0
- icdev/data/docs/features/phase-59-govcon-intelligence.md +535 -0
- icdev/data/docs/features/phase-60-cpmp.md +528 -0
- icdev/data/docs/features/phase-61-orchestration-improvements.md +534 -0
- icdev/data/docs/operations/dashboard-guide.md +354 -0
- icdev/data/docs/operations/deployment-guide.md +556 -0
- icdev/data/docs/operations/saas-admin-guide.md +439 -0
- icdev/data/docs/operations/security-operations-guide.md +733 -0
- icdev/data/docs/runbooks/backup-restore.md +412 -0
- icdev/data/docs/runbooks/troubleshooting.md +499 -0
- icdev/data/features/__init__.py +1 -0
- icdev/data/features/cicd_integration.feature +41 -0
- icdev/data/features/compliance_gates.feature +46 -0
- icdev/data/features/dashboard.feature +72 -0
- icdev/data/features/environment.py +25 -0
- icdev/data/features/project_management.feature +32 -0
- icdev/data/features/requirements_intake.feature +42 -0
- icdev/data/features/saas_platform.feature +53 -0
- icdev/data/features/security_scanning.feature +36 -0
- icdev/data/features/steps/__init__.py +1 -0
- icdev/data/features/steps/cicd_steps.py +465 -0
- icdev/data/features/steps/compliance_steps.py +308 -0
- icdev/data/features/steps/dashboard_steps.py +88 -0
- icdev/data/features/steps/project_steps.py +126 -0
- icdev/data/features/steps/requirements_intake_steps.py +689 -0
- icdev/data/features/steps/saas_platform_steps.py +572 -0
- icdev/data/features/steps/security_steps.py +236 -0
- icdev/data/features/steps/testing_steps.py +226 -0
- icdev/data/features/testing_pipeline.feature +42 -0
- icdev/data/goals/__init__.py +1 -0
- icdev/data/goals/agent_management.md +144 -0
- icdev/data/goals/agentic_generation.md +345 -0
- icdev/data/goals/agentic_threat_model.md +309 -0
- icdev/data/goals/ai_accountability.md +90 -0
- icdev/data/goals/ai_governance_intake.md +132 -0
- icdev/data/goals/ai_transparency.md +76 -0
- icdev/data/goals/atlas_integration.md +405 -0
- icdev/data/goals/ato_acceleration.md +139 -0
- icdev/data/goals/boundary_supply_chain.md +206 -0
- icdev/data/goals/build_app.md +544 -0
- icdev/data/goals/cicd_integration.md +86 -0
- icdev/data/goals/claude_dir_maintenance.md +77 -0
- icdev/data/goals/cli_capabilities.md +340 -0
- icdev/data/goals/cloud_agnostic.md +312 -0
- icdev/data/goals/code_intelligence.md +197 -0
- icdev/data/goals/code_review.md +94 -0
- icdev/data/goals/compliance_workflow.md +858 -0
- icdev/data/goals/continuous_harmonization.md +140 -0
- icdev/data/goals/cross_language_translation.md +171 -0
- icdev/data/goals/dashboard.md +142 -0
- icdev/data/goals/deploy_workflow.md +390 -0
- icdev/data/goals/devsecops_workflow.md +408 -0
- icdev/data/goals/evolutionary_intelligence.md +305 -0
- icdev/data/goals/external_integration.md +113 -0
- icdev/data/goals/framework_planning.md +63 -0
- icdev/data/goals/init_project.md +235 -0
- icdev/data/goals/innovation_engine.md +199 -0
- icdev/data/goals/integration_testing.md +189 -0
- icdev/data/goals/maintenance_audit.md +196 -0
- icdev/data/goals/manifest.md +56 -0
- icdev/data/goals/mbse_integration.md +504 -0
- icdev/data/goals/modernization_workflow.md +618 -0
- icdev/data/goals/monitoring.md +126 -0
- icdev/data/goals/mosa_workflow.md +463 -0
- icdev/data/goals/multi_agent_orchestration.md +68 -0
- icdev/data/goals/nlq_compliance.md +63 -0
- icdev/data/goals/observability.md +64 -0
- icdev/data/goals/observability_traceability_xai.md +154 -0
- icdev/data/goals/owasp_agentic_security.md +395 -0
- icdev/data/goals/parallel_cicd.md +61 -0
- icdev/data/goals/requirements_intake.md +213 -0
- icdev/data/goals/sbd_ivv_workflow.md +195 -0
- icdev/data/goals/security_categorization.md +133 -0
- icdev/data/goals/security_scan.md +381 -0
- icdev/data/goals/self_healing.md +120 -0
- icdev/data/goals/simulation_engine.md +111 -0
- icdev/data/goals/tdd_workflow.md +403 -0
- icdev/data/goals/zero_trust_architecture.md +403 -0
- icdev/data/hardprompts/__init__.py +1 -0
- icdev/data/hardprompts/agent/__init__.py +1 -0
- icdev/data/hardprompts/agent/agentic_architect.md +100 -0
- icdev/data/hardprompts/agent/debate_prompt.md +32 -0
- icdev/data/hardprompts/agent/fitness_evaluation.md +48 -0
- icdev/data/hardprompts/agent/governance_review.md +214 -0
- icdev/data/hardprompts/agent/reviewer_prompt.md +34 -0
- icdev/data/hardprompts/agent/skill_design.md +172 -0
- icdev/data/hardprompts/agent/task_decomposition.md +275 -0
- icdev/data/hardprompts/agent/veto_check_prompt.md +33 -0
- icdev/data/hardprompts/architect/__init__.py +1 -0
- icdev/data/hardprompts/architect/api_design.md +283 -0
- icdev/data/hardprompts/architect/data_model.md +277 -0
- icdev/data/hardprompts/architect/system_design.md +180 -0
- icdev/data/hardprompts/builder/__init__.py +1 -0
- icdev/data/hardprompts/builder/code_generation.md +59 -0
- icdev/data/hardprompts/builder/refactor.md +58 -0
- icdev/data/hardprompts/builder/scaffold_project.md +69 -0
- icdev/data/hardprompts/builder/test_generation.md +87 -0
- icdev/data/hardprompts/ci/__init__.py +1 -0
- icdev/data/hardprompts/ci/worktree_setup.md +35 -0
- icdev/data/hardprompts/compliance/__init__.py +1 -0
- icdev/data/hardprompts/compliance/cmmc_assessment.md +63 -0
- icdev/data/hardprompts/compliance/cssp_assessment.md +75 -0
- icdev/data/hardprompts/compliance/cui_marking.md +86 -0
- icdev/data/hardprompts/compliance/fedramp_assessment.md +55 -0
- icdev/data/hardprompts/compliance/ivv_assessment.md +96 -0
- icdev/data/hardprompts/compliance/poam_generation.md +57 -0
- icdev/data/hardprompts/compliance/sbd_assessment.md +101 -0
- icdev/data/hardprompts/compliance/security_categorization.md +74 -0
- icdev/data/hardprompts/compliance/ssp_generation.md +56 -0
- icdev/data/hardprompts/compliance/stig_evaluation.md +63 -0
- icdev/data/hardprompts/dashboard/__init__.py +1 -0
- icdev/data/hardprompts/dashboard/nlq_system_prompt.md +26 -0
- icdev/data/hardprompts/infra/__init__.py +1 -0
- icdev/data/hardprompts/infra/k8s_manifests.md +118 -0
- icdev/data/hardprompts/infra/pipeline_generation.md +160 -0
- icdev/data/hardprompts/infra/terraform_generation.md +92 -0
- icdev/data/hardprompts/integration/__init__.py +1 -0
- icdev/data/hardprompts/integration/approval_review.md +17 -0
- icdev/data/hardprompts/integration/jira_mapping.md +25 -0
- icdev/data/hardprompts/integration/servicenow_mapping.md +14 -0
- icdev/data/hardprompts/knowledge/__init__.py +1 -0
- icdev/data/hardprompts/knowledge/pattern_detection.md +73 -0
- icdev/data/hardprompts/knowledge/recommendation_engine.md +90 -0
- icdev/data/hardprompts/knowledge/root_cause_analysis.md +91 -0
- icdev/data/hardprompts/maintenance/__init__.py +1 -0
- icdev/data/hardprompts/maintenance/maintenance_assessment.md +82 -0
- icdev/data/hardprompts/mbse/__init__.py +1 -0
- icdev/data/hardprompts/mbse/digital_thread.md +67 -0
- icdev/data/hardprompts/mbse/model_import.md +62 -0
- icdev/data/hardprompts/mbse/model_to_code.md +65 -0
- icdev/data/hardprompts/modernization/__init__.py +1 -0
- icdev/data/hardprompts/modernization/legacy_analysis.md +93 -0
- icdev/data/hardprompts/modernization/migration_planning.md +150 -0
- icdev/data/hardprompts/modernization/seven_r_assessment.md +107 -0
- icdev/data/hardprompts/requirements/__init__.py +1 -0
- icdev/data/hardprompts/requirements/bdd_generation.md +35 -0
- icdev/data/hardprompts/requirements/clarification_prioritization.md +29 -0
- icdev/data/hardprompts/requirements/decomposition.md +60 -0
- icdev/data/hardprompts/requirements/document_extraction.md +45 -0
- icdev/data/hardprompts/requirements/gap_detection.md +70 -0
- icdev/data/hardprompts/requirements/intake_conversation.md +101 -0
- icdev/data/hardprompts/requirements/readiness_assessment.md +39 -0
- icdev/data/hardprompts/requirements/spec_quality.md +33 -0
- icdev/data/hardprompts/requirements/traceability_analysis.md +23 -0
- icdev/data/hardprompts/security/__init__.py +1 -0
- icdev/data/hardprompts/security/endpoint_security.md +78 -0
- icdev/data/hardprompts/security/threat_model.md +70 -0
- icdev/data/hardprompts/security/vulnerability_assessment.md +81 -0
- icdev/data/hardprompts/simulation/__init__.py +1 -0
- icdev/data/hardprompts/simulation/architecture_impact.md +27 -0
- icdev/data/hardprompts/simulation/coa_alternative.md +27 -0
- icdev/data/hardprompts/simulation/coa_generation.md +25 -0
- icdev/data/hardprompts/simulation/compliance_impact.md +28 -0
- icdev/data/hardprompts/simulation/cost_estimation.md +33 -0
- icdev/data/hardprompts/simulation/risk_assessment.md +28 -0
- icdev/data/hardprompts/translation/code_translation.md +68 -0
- icdev/data/hardprompts/translation/dependency_suggestion.md +44 -0
- icdev/data/hardprompts/translation/test_translation.md +64 -0
- icdev/data/hardprompts/translation/translation_repair.md +59 -0
- icdev/py.typed +0 -0
- icdev/tools/__init__.py +1 -0
- icdev/tools/_gen_formatter.py +12 -0
- icdev/tools/a2a/__init__.py +1 -0
- icdev/tools/a2a/agent_cards/architect.json +43 -0
- icdev/tools/a2a/agent_cards/builder.json +50 -0
- icdev/tools/a2a/agent_cards/compliance.json +57 -0
- icdev/tools/a2a/agent_cards/devsecops.json +71 -0
- icdev/tools/a2a/agent_cards/infra.json +57 -0
- icdev/tools/a2a/agent_cards/integration.json +57 -0
- icdev/tools/a2a/agent_cards/knowledge.json +43 -0
- icdev/tools/a2a/agent_cards/mbse.json +57 -0
- icdev/tools/a2a/agent_cards/modernization.json +50 -0
- icdev/tools/a2a/agent_cards/monitor.json +43 -0
- icdev/tools/a2a/agent_cards/orchestrator.json +36 -0
- icdev/tools/a2a/agent_cards/requirements_analyst.json +64 -0
- icdev/tools/a2a/agent_cards/security.json +50 -0
- icdev/tools/a2a/agent_cards/simulation.json +57 -0
- icdev/tools/a2a/agent_cards/supply_chain.json +50 -0
- icdev/tools/a2a/agent_client.py +349 -0
- icdev/tools/a2a/agent_registry.py +412 -0
- icdev/tools/a2a/agent_server.py +579 -0
- icdev/tools/a2a/task.py +200 -0
- icdev/tools/agent/__init__.py +2 -0
- icdev/tools/agent/a2a_agent_card_generator.py +285 -0
- icdev/tools/agent/a2a_discovery_server.py +250 -0
- icdev/tools/agent/agent_executor.py +529 -0
- icdev/tools/agent/agent_memory.py +557 -0
- icdev/tools/agent/agent_models.py +51 -0
- icdev/tools/agent/atlas_critique.py +908 -0
- icdev/tools/agent/authority.py +443 -0
- icdev/tools/agent/bedrock_client.py +1075 -0
- icdev/tools/agent/collaboration.py +871 -0
- icdev/tools/agent/dispatcher_mode.py +665 -0
- icdev/tools/agent/mailbox.py +575 -0
- icdev/tools/agent/prompt_chain_executor.py +1064 -0
- icdev/tools/agent/session_purpose.py +350 -0
- icdev/tools/agent/skill_router.py +638 -0
- icdev/tools/agent/skill_selector.py +486 -0
- icdev/tools/agent/team_orchestrator.py +1108 -0
- icdev/tools/agent/token_tracker.py +290 -0
- icdev/tools/analysis/__init__.py +1 -0
- icdev/tools/analysis/code_analyzer.py +780 -0
- icdev/tools/analysis/runtime_feedback.py +389 -0
- icdev/tools/audit/__init__.py +1 -0
- icdev/tools/audit/audit_logger.py +196 -0
- icdev/tools/audit/audit_query.py +157 -0
- icdev/tools/audit/decision_recorder.py +72 -0
- icdev/tools/builder/__init__.py +1 -0
- icdev/tools/builder/agentic_fitness.py +534 -0
- icdev/tools/builder/agentic_test_templates/test_a2a_callback.py +117 -0
- icdev/tools/builder/agentic_test_templates/test_a2a_lifecycle.feature +52 -0
- icdev/tools/builder/agentic_test_templates/test_agent_card.feature +37 -0
- icdev/tools/builder/agentic_test_templates/test_agent_health.py +128 -0
- icdev/tools/builder/agentic_test_templates/test_memory_system.feature +50 -0
- icdev/tools/builder/agentic_test_templates/test_skill_execution.feature +40 -0
- icdev/tools/builder/app_blueprint.py +1583 -0
- icdev/tools/builder/child_app_generator.py +2852 -0
- icdev/tools/builder/claude_md_generator.py +1734 -0
- icdev/tools/builder/code_generator.py +3703 -0
- icdev/tools/builder/db_init_generator.py +1709 -0
- icdev/tools/builder/dev_profile_manager.py +954 -0
- icdev/tools/builder/formatter.py +768 -0
- icdev/tools/builder/goal_adapter.py +592 -0
- icdev/tools/builder/gotcha_validator.py +812 -0
- icdev/tools/builder/language_support.py +441 -0
- icdev/tools/builder/linter.py +976 -0
- icdev/tools/builder/profile_detector.py +657 -0
- icdev/tools/builder/profile_md_generator.py +723 -0
- icdev/tools/builder/scaffolder.py +1590 -0
- icdev/tools/builder/scaffolder_extended.py +1771 -0
- icdev/tools/builder/test_writer.py +950 -0
- icdev/tools/ci/__init__.py +2 -0
- icdev/tools/ci/connectors/__init__.py +2 -0
- icdev/tools/ci/connectors/base_connector.py +80 -0
- icdev/tools/ci/connectors/connector_registry.py +188 -0
- icdev/tools/ci/connectors/mattermost_connector.py +159 -0
- icdev/tools/ci/connectors/slack_connector.py +197 -0
- icdev/tools/ci/core/__init__.py +2 -0
- icdev/tools/ci/core/air_gap_detector.py +115 -0
- icdev/tools/ci/core/comment_handler.py +192 -0
- icdev/tools/ci/core/conversation_manager.py +479 -0
- icdev/tools/ci/core/event_envelope.py +500 -0
- icdev/tools/ci/core/event_router.py +443 -0
- icdev/tools/ci/core/failure_parser.py +397 -0
- icdev/tools/ci/core/recovery_engine.py +527 -0
- icdev/tools/ci/modules/__init__.py +2 -0
- icdev/tools/ci/modules/agent.py +271 -0
- icdev/tools/ci/modules/git_ops.py +175 -0
- icdev/tools/ci/modules/state.py +117 -0
- icdev/tools/ci/modules/vcs.py +303 -0
- icdev/tools/ci/modules/workflow_ops.py +295 -0
- icdev/tools/ci/modules/worktree.py +340 -0
- icdev/tools/ci/pipeline_config_generator.py +558 -0
- icdev/tools/ci/triggers/__init__.py +2 -0
- icdev/tools/ci/triggers/gitlab_task_monitor.py +330 -0
- icdev/tools/ci/triggers/poll_trigger.py +237 -0
- icdev/tools/ci/triggers/webhook_server.py +356 -0
- icdev/tools/ci/workflows/__init__.py +2 -0
- icdev/tools/ci/workflows/icdev_build.py +140 -0
- icdev/tools/ci/workflows/icdev_comply.py +284 -0
- icdev/tools/ci/workflows/icdev_document.py +152 -0
- icdev/tools/ci/workflows/icdev_e2e.py +188 -0
- icdev/tools/ci/workflows/icdev_patch.py +186 -0
- icdev/tools/ci/workflows/icdev_plan.py +202 -0
- icdev/tools/ci/workflows/icdev_plan_build.py +41 -0
- icdev/tools/ci/workflows/icdev_plan_build_test.py +46 -0
- icdev/tools/ci/workflows/icdev_plan_build_test_review.py +47 -0
- icdev/tools/ci/workflows/icdev_review.py +126 -0
- icdev/tools/ci/workflows/icdev_sdlc.py +261 -0
- icdev/tools/ci/workflows/icdev_test.py +240 -0
- icdev/tools/cli/__init__.py +1 -0
- icdev/tools/cli/output_formatter.py +756 -0
- icdev/tools/cli_formatter.py +42 -0
- icdev/tools/cloud/__init__.py +11 -0
- icdev/tools/cloud/cloud_mode_manager.py +364 -0
- icdev/tools/cloud/csp_changelog.py +383 -0
- icdev/tools/cloud/csp_health_checker.py +268 -0
- icdev/tools/cloud/csp_monitor.py +951 -0
- icdev/tools/cloud/iam_provider.py +593 -0
- icdev/tools/cloud/kms_provider.py +346 -0
- icdev/tools/cloud/monitoring_provider.py +628 -0
- icdev/tools/cloud/provider_factory.py +376 -0
- icdev/tools/cloud/region_validator.py +345 -0
- icdev/tools/cloud/registry_provider.py +563 -0
- icdev/tools/cloud/secrets_provider.py +486 -0
- icdev/tools/cloud/storage_provider.py +446 -0
- icdev/tools/compat/__init__.py +21 -0
- icdev/tools/compat/cli_harmonizer.py +251 -0
- icdev/tools/compat/datetime_utils.py +18 -0
- icdev/tools/compat/db_utils.py +160 -0
- icdev/tools/compat/platform_utils.py +123 -0
- icdev/tools/compliance/__init__.py +1 -0
- icdev/tools/compliance/accountability_manager.py +397 -0
- icdev/tools/compliance/ai_accountability_audit.py +294 -0
- icdev/tools/compliance/ai_impact_assessor.py +273 -0
- icdev/tools/compliance/ai_incident_response.py +301 -0
- icdev/tools/compliance/ai_inventory_manager.py +239 -0
- icdev/tools/compliance/ai_reassessment_scheduler.py +256 -0
- icdev/tools/compliance/ai_transparency_audit.py +248 -0
- icdev/tools/compliance/atlas_assessor.py +278 -0
- icdev/tools/compliance/atlas_report_generator.py +1211 -0
- icdev/tools/compliance/base_assessor.py +597 -0
- icdev/tools/compliance/cato_monitor.py +1385 -0
- icdev/tools/compliance/cato_scheduler.py +699 -0
- icdev/tools/compliance/cjis_assessor.py +76 -0
- icdev/tools/compliance/classification_manager.py +1353 -0
- icdev/tools/compliance/cmmc_assessor.py +1491 -0
- icdev/tools/compliance/cmmc_report_generator.py +1100 -0
- icdev/tools/compliance/compliance_detector.py +463 -0
- icdev/tools/compliance/compliance_exporter.py +427 -0
- icdev/tools/compliance/compliance_status.py +825 -0
- icdev/tools/compliance/control_mapper.py +505 -0
- icdev/tools/compliance/crosswalk_engine.py +1203 -0
- icdev/tools/compliance/cssp_assessor.py +1045 -0
- icdev/tools/compliance/cssp_evidence_collector.py +729 -0
- icdev/tools/compliance/cssp_report_generator.py +1116 -0
- icdev/tools/compliance/cui_marker.py +388 -0
- icdev/tools/compliance/diagram_validator.py +600 -0
- icdev/tools/compliance/emass/__init__.py +2 -0
- icdev/tools/compliance/emass/emass_client.py +840 -0
- icdev/tools/compliance/emass/emass_export.py +777 -0
- icdev/tools/compliance/emass/emass_sync.py +826 -0
- icdev/tools/compliance/eu_ai_act_classifier.py +194 -0
- icdev/tools/compliance/evidence_collector.py +468 -0
- icdev/tools/compliance/fairness_assessor.py +316 -0
- icdev/tools/compliance/fedramp_assessor.py +1808 -0
- icdev/tools/compliance/fedramp_authorization_packager.py +137 -0
- icdev/tools/compliance/fedramp_ksi_generator.py +355 -0
- icdev/tools/compliance/fedramp_report_generator.py +1128 -0
- icdev/tools/compliance/fips199_categorizer.py +881 -0
- icdev/tools/compliance/fips200_validator.py +315 -0
- icdev/tools/compliance/gao_ai_assessor.py +231 -0
- icdev/tools/compliance/gao_evidence_builder.py +308 -0
- icdev/tools/compliance/hipaa_assessor.py +78 -0
- icdev/tools/compliance/hitrust_assessor.py +49 -0
- icdev/tools/compliance/incident_response_plan.py +718 -0
- icdev/tools/compliance/iso27001_assessor.py +92 -0
- icdev/tools/compliance/iso42001_assessor.py +114 -0
- icdev/tools/compliance/ivv_assessor.py +2327 -0
- icdev/tools/compliance/ivv_report_generator.py +1662 -0
- icdev/tools/compliance/model_card_generator.py +297 -0
- icdev/tools/compliance/mosa_assessor.py +117 -0
- icdev/tools/compliance/multi_regime_assessor.py +451 -0
- icdev/tools/compliance/narrative_generator.py +1013 -0
- icdev/tools/compliance/nist_800_207_assessor.py +191 -0
- icdev/tools/compliance/nist_ai_600_1_assessor.py +188 -0
- icdev/tools/compliance/nist_ai_rmf_assessor.py +110 -0
- icdev/tools/compliance/nist_lookup.py +245 -0
- icdev/tools/compliance/omb_m25_21_assessor.py +228 -0
- icdev/tools/compliance/omb_m26_04_assessor.py +188 -0
- icdev/tools/compliance/oscal_catalog_adapter.py +395 -0
- icdev/tools/compliance/oscal_generator.py +2170 -0
- icdev/tools/compliance/oscal_tools.py +1182 -0
- icdev/tools/compliance/owasp_agentic_assessor.py +226 -0
- icdev/tools/compliance/owasp_asi_assessor.py +200 -0
- icdev/tools/compliance/owasp_llm_assessor.py +244 -0
- icdev/tools/compliance/pci_dss_assessor.py +80 -0
- icdev/tools/compliance/pi_compliance_tracker.py +1461 -0
- icdev/tools/compliance/poam_generator.py +405 -0
- icdev/tools/compliance/resolve_marking.py +283 -0
- icdev/tools/compliance/sbd_assessor.py +2068 -0
- icdev/tools/compliance/sbd_report_generator.py +1236 -0
- icdev/tools/compliance/sbom_generator.py +1008 -0
- icdev/tools/compliance/siem_config_generator.py +674 -0
- icdev/tools/compliance/slsa_attestation_generator.py +490 -0
- icdev/tools/compliance/soc2_assessor.py +77 -0
- icdev/tools/compliance/ssp_generator.py +573 -0
- icdev/tools/compliance/stig_checker.py +727 -0
- icdev/tools/compliance/swft_evidence_bundler.py +337 -0
- icdev/tools/compliance/system_card_generator.py +309 -0
- icdev/tools/compliance/traceability_matrix.py +1281 -0
- icdev/tools/compliance/universal_classification_manager.py +1172 -0
- icdev/tools/compliance/xacta/__init__.py +2 -0
- icdev/tools/compliance/xacta/xacta_client.py +449 -0
- icdev/tools/compliance/xacta/xacta_export.py +557 -0
- icdev/tools/compliance/xacta/xacta_sync.py +333 -0
- icdev/tools/compliance/xai_assessor.py +231 -0
- icdev/tools/dashboard/__init__.py +1 -0
- icdev/tools/dashboard/api/__init__.py +1 -0
- icdev/tools/dashboard/api/_pipeline_state.py +17 -0
- icdev/tools/dashboard/api/activity.py +206 -0
- icdev/tools/dashboard/api/admin.py +176 -0
- icdev/tools/dashboard/api/agents.py +53 -0
- icdev/tools/dashboard/api/ai_accountability.py +163 -0
- icdev/tools/dashboard/api/ai_transparency.py +198 -0
- icdev/tools/dashboard/api/audit.py +58 -0
- icdev/tools/dashboard/api/batch.py +666 -0
- icdev/tools/dashboard/api/chat.py +241 -0
- icdev/tools/dashboard/api/cicd.py +219 -0
- icdev/tools/dashboard/api/code_quality.py +223 -0
- icdev/tools/dashboard/api/compliance.py +171 -0
- icdev/tools/dashboard/api/cpmp.py +915 -0
- icdev/tools/dashboard/api/diagrams.py +65 -0
- icdev/tools/dashboard/api/events.py +250 -0
- icdev/tools/dashboard/api/evidence.py +99 -0
- icdev/tools/dashboard/api/fedramp_20x.py +77 -0
- icdev/tools/dashboard/api/govcon.py +1095 -0
- icdev/tools/dashboard/api/intake.py +1171 -0
- icdev/tools/dashboard/api/lineage.py +163 -0
- icdev/tools/dashboard/api/metrics.py +155 -0
- icdev/tools/dashboard/api/nlq.py +72 -0
- icdev/tools/dashboard/api/orchestration.py +472 -0
- icdev/tools/dashboard/api/oscal.py +183 -0
- icdev/tools/dashboard/api/prod_audit.py +183 -0
- icdev/tools/dashboard/api/projects.py +191 -0
- icdev/tools/dashboard/api/proposals.py +1084 -0
- icdev/tools/dashboard/api/traces.py +363 -0
- icdev/tools/dashboard/api/usage.py +234 -0
- icdev/tools/dashboard/app.py +1986 -0
- icdev/tools/dashboard/auth.py +500 -0
- icdev/tools/dashboard/byok.py +245 -0
- icdev/tools/dashboard/chat_manager.py +675 -0
- icdev/tools/dashboard/config.py +116 -0
- icdev/tools/dashboard/diagram_definitions.py +642 -0
- icdev/tools/dashboard/nlq_processor.py +323 -0
- icdev/tools/dashboard/phase_loader.py +136 -0
- icdev/tools/dashboard/sse_manager.py +89 -0
- icdev/tools/dashboard/state_tracker.py +267 -0
- icdev/tools/dashboard/static/css/style.css +706 -0
- icdev/tools/dashboard/static/css/ux.css +2047 -0
- icdev/tools/dashboard/static/js/activity.js +322 -0
- icdev/tools/dashboard/static/js/api.js +161 -0
- icdev/tools/dashboard/static/js/batch.js +814 -0
- icdev/tools/dashboard/static/js/charts.js +618 -0
- icdev/tools/dashboard/static/js/chat.js +1514 -0
- icdev/tools/dashboard/static/js/kanban.js +113 -0
- icdev/tools/dashboard/static/js/live.js +569 -0
- icdev/tools/dashboard/static/js/mermaid-icdev.js +332 -0
- icdev/tools/dashboard/static/js/proposals.js +588 -0
- icdev/tools/dashboard/static/js/shortcuts.js +544 -0
- icdev/tools/dashboard/static/js/tables.js +652 -0
- icdev/tools/dashboard/static/js/tour.js +524 -0
- icdev/tools/dashboard/static/js/ux.js +942 -0
- icdev/tools/dashboard/templates/404.html +10 -0
- icdev/tools/dashboard/templates/activity.html +80 -0
- icdev/tools/dashboard/templates/admin/users.html +144 -0
- icdev/tools/dashboard/templates/ai_accountability.html +235 -0
- icdev/tools/dashboard/templates/ai_transparency.html +263 -0
- icdev/tools/dashboard/templates/base.html +104 -0
- icdev/tools/dashboard/templates/batch.html +23 -0
- icdev/tools/dashboard/templates/chat.html +332 -0
- icdev/tools/dashboard/templates/children.html +149 -0
- icdev/tools/dashboard/templates/cicd.html +253 -0
- icdev/tools/dashboard/templates/code_quality.html +214 -0
- icdev/tools/dashboard/templates/cpmp/cor_detail.html +220 -0
- icdev/tools/dashboard/templates/cpmp/cor_portal.html +91 -0
- icdev/tools/dashboard/templates/cpmp/deliverable_detail.html +197 -0
- icdev/tools/dashboard/templates/cpmp/detail.html +578 -0
- icdev/tools/dashboard/templates/cpmp/portfolio.html +202 -0
- icdev/tools/dashboard/templates/dev_profiles.html +304 -0
- icdev/tools/dashboard/templates/diagrams.html +224 -0
- icdev/tools/dashboard/templates/events/timeline.html +232 -0
- icdev/tools/dashboard/templates/evidence.html +134 -0
- icdev/tools/dashboard/templates/fedramp_20x.html +207 -0
- icdev/tools/dashboard/templates/gateway.html +244 -0
- icdev/tools/dashboard/templates/govcon/capabilities.html +135 -0
- icdev/tools/dashboard/templates/govcon/pipeline.html +214 -0
- icdev/tools/dashboard/templates/govcon/requirements.html +120 -0
- icdev/tools/dashboard/templates/index.html +254 -0
- icdev/tools/dashboard/templates/lineage.html +141 -0
- icdev/tools/dashboard/templates/login.html +51 -0
- icdev/tools/dashboard/templates/monitoring/overview.html +193 -0
- icdev/tools/dashboard/templates/orchestration/dashboard.html +545 -0
- icdev/tools/dashboard/templates/oscal.html +263 -0
- icdev/tools/dashboard/templates/phases.html +150 -0
- icdev/tools/dashboard/templates/prod_audit.html +280 -0
- icdev/tools/dashboard/templates/profile.html +183 -0
- icdev/tools/dashboard/templates/projects/detail.html +583 -0
- icdev/tools/dashboard/templates/projects/list.html +47 -0
- icdev/tools/dashboard/templates/proposals/detail.html +1253 -0
- icdev/tools/dashboard/templates/proposals/list.html +179 -0
- icdev/tools/dashboard/templates/proposals/section_detail.html +193 -0
- icdev/tools/dashboard/templates/provenance.html +181 -0
- icdev/tools/dashboard/templates/query/nlq.html +234 -0
- icdev/tools/dashboard/templates/quick_paths.html +69 -0
- icdev/tools/dashboard/templates/traces.html +155 -0
- icdev/tools/dashboard/templates/translation_detail.html +199 -0
- icdev/tools/dashboard/templates/translations.html +162 -0
- icdev/tools/dashboard/templates/usage.html +225 -0
- icdev/tools/dashboard/templates/wizard.html +539 -0
- icdev/tools/dashboard/templates/xai.html +208 -0
- icdev/tools/dashboard/ux_helpers.py +962 -0
- icdev/tools/dashboard/websocket.py +81 -0
- icdev/tools/db/__init__.py +1 -0
- icdev/tools/db/backup.py +312 -0
- icdev/tools/db/backup_manager.py +832 -0
- icdev/tools/db/init_icdev_db.py +5900 -0
- icdev/tools/db/migrate.py +178 -0
- icdev/tools/db/migration_runner.py +549 -0
- icdev/tools/db/migrations/001_baseline/meta.json +9 -0
- icdev/tools/db/migrations/001_baseline/up.py +68 -0
- icdev/tools/db/migrations/002_memory_enhancements/down.sql +8 -0
- icdev/tools/db/migrations/002_memory_enhancements/meta.json +9 -0
- icdev/tools/db/migrations/002_memory_enhancements/up.py +118 -0
- icdev/tools/db/migrations/003_dev_profiles/meta.json +8 -0
- icdev/tools/db/migrations/003_dev_profiles/up.py +93 -0
- icdev/tools/db/migrations/004_innovation_engine/down.py +19 -0
- icdev/tools/db/migrations/004_innovation_engine/up.py +227 -0
- icdev/tools/db/migrations/005_phase_37_ai_security/down.py +19 -0
- icdev/tools/db/migrations/005_phase_37_ai_security/up.py +258 -0
- icdev/tools/db/migrations/006_phase_36_evolution/down.py +21 -0
- icdev/tools/db/migrations/006_phase_36_evolution/up.py +323 -0
- icdev/tools/db/migrations/007_phase_38_cloud/down.py +14 -0
- icdev/tools/db/migrations/007_phase_38_cloud/up.py +110 -0
- icdev/tools/db/migrations/008_phase36_37_integration/up.py +55 -0
- icdev/tools/db/migrations/__init__.py +2 -0
- icdev/tools/devsecops/__init__.py +2 -0
- icdev/tools/devsecops/attestation_manager.py +458 -0
- icdev/tools/devsecops/network_segmentation_generator.py +614 -0
- icdev/tools/devsecops/pdp_config_generator.py +1256 -0
- icdev/tools/devsecops/pipeline_security_generator.py +484 -0
- icdev/tools/devsecops/policy_generator.py +653 -0
- icdev/tools/devsecops/profile_manager.py +388 -0
- icdev/tools/devsecops/service_mesh_generator.py +1073 -0
- icdev/tools/devsecops/zta_maturity_scorer.py +368 -0
- icdev/tools/devsecops/zta_terraform_generator.py +1303 -0
- icdev/tools/dx/__init__.py +3 -0
- icdev/tools/dx/companion.py +266 -0
- icdev/tools/dx/instruction_generator.py +753 -0
- icdev/tools/dx/mcp_config_generator.py +282 -0
- icdev/tools/dx/skill_translator.py +425 -0
- icdev/tools/dx/tool_detector.py +144 -0
- icdev/tools/extensions/__init__.py +21 -0
- icdev/tools/extensions/builtins/010_ai_governance_chat.py +277 -0
- icdev/tools/extensions/builtins/__init__.py +2 -0
- icdev/tools/extensions/extension_manager.py +455 -0
- icdev/tools/infra/__init__.py +1 -0
- icdev/tools/infra/ansible_generator.py +869 -0
- icdev/tools/infra/dockerfile_generator.py +361 -0
- icdev/tools/infra/infra_status.py +393 -0
- icdev/tools/infra/ironbank_metadata_generator.py +411 -0
- icdev/tools/infra/k8s_generator.py +1002 -0
- icdev/tools/infra/pipeline_generator.py +832 -0
- icdev/tools/infra/rollback.py +400 -0
- icdev/tools/infra/terraform_generator.py +1142 -0
- icdev/tools/infra/terraform_generator_azure.py +1254 -0
- icdev/tools/infra/terraform_generator_gcp.py +953 -0
- icdev/tools/infra/terraform_generator_ibm.py +360 -0
- icdev/tools/infra/terraform_generator_oci.py +919 -0
- icdev/tools/infra/terraform_generator_onprem.py +319 -0
- icdev/tools/innovation/__init__.py +8 -0
- icdev/tools/innovation/competitive_intel.py +492 -0
- icdev/tools/innovation/innovation_manager.py +681 -0
- icdev/tools/innovation/introspective_analyzer.py +774 -0
- icdev/tools/innovation/register_external_patterns.py +440 -0
- icdev/tools/innovation/signal_ranker.py +1038 -0
- icdev/tools/innovation/solution_generator.py +697 -0
- icdev/tools/innovation/standards_monitor.py +466 -0
- icdev/tools/innovation/trend_detector.py +1046 -0
- icdev/tools/innovation/triage_engine.py +1149 -0
- icdev/tools/innovation/web_scanner.py +894 -0
- icdev/tools/installer/__init__.py +1 -0
- icdev/tools/installer/compliance_configurator.py +637 -0
- icdev/tools/installer/installer.py +1711 -0
- icdev/tools/installer/module_registry.py +805 -0
- icdev/tools/installer/platform_setup.py +961 -0
- icdev/tools/integration/__init__.py +2 -0
- icdev/tools/integration/approval_manager.py +561 -0
- icdev/tools/integration/doors_exporter.py +627 -0
- icdev/tools/integration/gitlab_connector.py +784 -0
- icdev/tools/integration/jira_connector.py +774 -0
- icdev/tools/integration/servicenow_connector.py +693 -0
- icdev/tools/knowledge/__init__.py +1 -0
- icdev/tools/knowledge/knowledge_ingest.py +293 -0
- icdev/tools/knowledge/pattern_detector.py +693 -0
- icdev/tools/knowledge/recommendation_engine.py +461 -0
- icdev/tools/knowledge/self_heal_analyzer.py +504 -0
- icdev/tools/llm/__init__.py +72 -0
- icdev/tools/llm/anthropic_provider.py +170 -0
- icdev/tools/llm/azure_openai_provider.py +338 -0
- icdev/tools/llm/bedrock_provider.py +315 -0
- icdev/tools/llm/embedding_provider.py +438 -0
- icdev/tools/llm/gemini_provider.py +381 -0
- icdev/tools/llm/ibm_watsonx_provider.py +232 -0
- icdev/tools/llm/oci_genai_provider.py +462 -0
- icdev/tools/llm/ollama_provider.py +340 -0
- icdev/tools/llm/openai_provider.py +225 -0
- icdev/tools/llm/provider.py +355 -0
- icdev/tools/llm/provider_sdk.py +175 -0
- icdev/tools/llm/router.py +780 -0
- icdev/tools/llm/vertex_ai_provider.py +374 -0
- icdev/tools/maintenance/__init__.py +2 -0
- icdev/tools/maintenance/dependency_scanner.py +1030 -0
- icdev/tools/maintenance/maintenance_auditor.py +815 -0
- icdev/tools/maintenance/remediation_engine.py +966 -0
- icdev/tools/maintenance/vulnerability_checker.py +987 -0
- icdev/tools/mbse/__init__.py +3 -0
- icdev/tools/mbse/des_assessor.py +1186 -0
- icdev/tools/mbse/des_report_generator.py +800 -0
- icdev/tools/mbse/diagram_extractor.py +811 -0
- icdev/tools/mbse/digital_thread.py +1665 -0
- icdev/tools/mbse/model_code_generator.py +1122 -0
- icdev/tools/mbse/model_control_mapper.py +420 -0
- icdev/tools/mbse/pi_model_tracker.py +1093 -0
- icdev/tools/mbse/reqif_parser.py +1483 -0
- icdev/tools/mbse/sync_engine.py +1805 -0
- icdev/tools/mbse/xmi_parser.py +1573 -0
- icdev/tools/mcp/__init__.py +1 -0
- icdev/tools/mcp/base_server.py +535 -0
- icdev/tools/mcp/builder_server.py +725 -0
- icdev/tools/mcp/compliance_server.py +1407 -0
- icdev/tools/mcp/context_indexer.py +199 -0
- icdev/tools/mcp/context_server.py +305 -0
- icdev/tools/mcp/core_server.py +679 -0
- icdev/tools/mcp/devsecops_server.py +432 -0
- icdev/tools/mcp/gap_handlers.py +1079 -0
- icdev/tools/mcp/gateway_server.py +339 -0
- icdev/tools/mcp/generate_registry.py +623 -0
- icdev/tools/mcp/infra_server.py +264 -0
- icdev/tools/mcp/innovation_server.py +316 -0
- icdev/tools/mcp/integration_server.py +527 -0
- icdev/tools/mcp/knowledge_server.py +429 -0
- icdev/tools/mcp/maintenance_server.py +248 -0
- icdev/tools/mcp/marketplace_server.py +499 -0
- icdev/tools/mcp/mbse_server.py +398 -0
- icdev/tools/mcp/modernization_server.py +496 -0
- icdev/tools/mcp/observability_server.py +354 -0
- icdev/tools/mcp/requirements_server.py +415 -0
- icdev/tools/mcp/simulation_server.py +468 -0
- icdev/tools/mcp/standalone/__init__.py +2 -0
- icdev/tools/mcp/standalone/builder.py +59 -0
- icdev/tools/mcp/standalone/compliance.py +59 -0
- icdev/tools/mcp/standalone/core.py +59 -0
- icdev/tools/mcp/standalone/knowledge.py +59 -0
- icdev/tools/mcp/standalone/maintenance.py +59 -0
- icdev/tools/mcp/supply_chain_server.py +476 -0
- icdev/tools/mcp/tool_registry.py +2008 -0
- icdev/tools/mcp/unified_server.py +158 -0
- icdev/tools/memory/__init__.py +2 -0
- icdev/tools/memory/auto_capture.py +347 -0
- icdev/tools/memory/embed_memory.py +158 -0
- icdev/tools/memory/history_compressor.py +334 -0
- icdev/tools/memory/hybrid_search.py +236 -0
- icdev/tools/memory/maintenance_cron.py +289 -0
- icdev/tools/memory/memory_consolidation.py +444 -0
- icdev/tools/memory/memory_db.py +133 -0
- icdev/tools/memory/memory_read.py +102 -0
- icdev/tools/memory/memory_write.py +222 -0
- icdev/tools/memory/semantic_search.py +139 -0
- icdev/tools/memory/time_decay.py +435 -0
- icdev/tools/modernization/__init__.py +3 -0
- icdev/tools/modernization/architecture_extractor.py +734 -0
- icdev/tools/modernization/compliance_bridge.py +1499 -0
- icdev/tools/modernization/db_migration_planner.py +1385 -0
- icdev/tools/modernization/doc_generator.py +1428 -0
- icdev/tools/modernization/framework_migrator.py +1525 -0
- icdev/tools/modernization/legacy_analyzer.py +1948 -0
- icdev/tools/modernization/migration_code_generator.py +1639 -0
- icdev/tools/modernization/migration_report_generator.py +1653 -0
- icdev/tools/modernization/migration_tracker.py +1726 -0
- icdev/tools/modernization/monolith_decomposer.py +1508 -0
- icdev/tools/modernization/seven_r_assessor.py +1658 -0
- icdev/tools/modernization/strangler_fig_manager.py +1705 -0
- icdev/tools/modernization/ui_analyzer.py +771 -0
- icdev/tools/modernization/version_migrator.py +1392 -0
- icdev/tools/monitor/__init__.py +1 -0
- icdev/tools/monitor/alert_correlator.py +495 -0
- icdev/tools/monitor/auto_resolver.py +612 -0
- icdev/tools/monitor/health_checker.py +509 -0
- icdev/tools/monitor/heartbeat_daemon.py +792 -0
- icdev/tools/monitor/log_analyzer.py +516 -0
- icdev/tools/monitor/metric_collector.py +496 -0
- icdev/tools/mosa/__init__.py +10 -0
- icdev/tools/mosa/icd_generator.py +370 -0
- icdev/tools/mosa/modular_design_analyzer.py +683 -0
- icdev/tools/mosa/mosa_code_enforcer.py +349 -0
- icdev/tools/mosa/tsp_generator.py +265 -0
- icdev/tools/observability/__init__.py +100 -0
- icdev/tools/observability/genai_attributes.py +88 -0
- icdev/tools/observability/instrumentation.py +140 -0
- icdev/tools/observability/mlflow_exporter.py +194 -0
- icdev/tools/observability/otel_tracer.py +168 -0
- icdev/tools/observability/provenance/__init__.py +3 -0
- icdev/tools/observability/provenance/prov_recorder.py +324 -0
- icdev/tools/observability/shap/__init__.py +3 -0
- icdev/tools/observability/shap/agent_shap.py +275 -0
- icdev/tools/observability/sqlite_tracer.py +361 -0
- icdev/tools/observability/trace_context.py +205 -0
- icdev/tools/observability/tracer.py +230 -0
- icdev/tools/orchestration/__init__.py +2 -0
- icdev/tools/orchestration/workflow_composer.py +361 -0
- icdev/tools/project/__init__.py +1 -0
- icdev/tools/project/manifest_loader.py +418 -0
- icdev/tools/project/project_create.py +350 -0
- icdev/tools/project/project_list.py +174 -0
- icdev/tools/project/project_scaffold.py +1715 -0
- icdev/tools/project/project_status.py +479 -0
- icdev/tools/project/session_context_builder.py +757 -0
- icdev/tools/project/validate_manifest.py +55 -0
- icdev/tools/registry/__init__.py +10 -0
- icdev/tools/registry/absorption_engine.py +832 -0
- icdev/tools/registry/capability_evaluator.py +668 -0
- icdev/tools/registry/child_registry.py +617 -0
- icdev/tools/registry/cross_pollinator.py +1065 -0
- icdev/tools/registry/genome_manager.py +671 -0
- icdev/tools/registry/learning_collector.py +912 -0
- icdev/tools/registry/propagation_manager.py +942 -0
- icdev/tools/registry/staging_manager.py +742 -0
- icdev/tools/registry/telemetry_collector.py +423 -0
- icdev/tools/requirements/__init__.py +1 -0
- icdev/tools/requirements/ai_governance_scorer.py +208 -0
- icdev/tools/requirements/boundary_analyzer.py +1293 -0
- icdev/tools/requirements/clarification_engine.py +618 -0
- icdev/tools/requirements/complexity_scorer.py +387 -0
- icdev/tools/requirements/consistency_analyzer.py +803 -0
- icdev/tools/requirements/constitution_manager.py +605 -0
- icdev/tools/requirements/decomposition_engine.py +778 -0
- icdev/tools/requirements/document_extractor.py +1016 -0
- icdev/tools/requirements/elicitation_techniques.py +519 -0
- icdev/tools/requirements/gap_detector.py +271 -0
- icdev/tools/requirements/intake_engine.py +2188 -0
- icdev/tools/requirements/prd_generator.py +847 -0
- icdev/tools/requirements/prd_validator.py +595 -0
- icdev/tools/requirements/readiness_scorer.py +313 -0
- icdev/tools/requirements/spec_organizer.py +1029 -0
- icdev/tools/requirements/spec_quality_checker.py +1097 -0
- icdev/tools/requirements/traceability_builder.py +579 -0
- icdev/tools/resilience/__init__.py +34 -0
- icdev/tools/resilience/circuit_breaker.py +340 -0
- icdev/tools/resilience/correlation.py +150 -0
- icdev/tools/resilience/errors.py +81 -0
- icdev/tools/resilience/retry.py +95 -0
- icdev/tools/schemas/__init__.py +27 -0
- icdev/tools/schemas/chat.py +61 -0
- icdev/tools/schemas/compliance.py +56 -0
- icdev/tools/schemas/core.py +85 -0
- icdev/tools/schemas/innovation.py +37 -0
- icdev/tools/schemas/validation.py +109 -0
- icdev/tools/sdk/__init__.py +3 -0
- icdev/tools/sdk/icdev_client.py +218 -0
- icdev/tools/security/__init__.py +1 -0
- icdev/tools/security/agent_output_validator.py +330 -0
- icdev/tools/security/agent_trust_scorer.py +466 -0
- icdev/tools/security/ai_bom_generator.py +725 -0
- icdev/tools/security/ai_telemetry_logger.py +469 -0
- icdev/tools/security/atlas_red_team.py +543 -0
- icdev/tools/security/code_pattern_scanner.py +378 -0
- icdev/tools/security/confabulation_detector.py +271 -0
- icdev/tools/security/container_scanner.py +491 -0
- icdev/tools/security/dependency_auditor.py +944 -0
- icdev/tools/security/endpoint_security_scanner.py +579 -0
- icdev/tools/security/mcp_tool_authorizer.py +243 -0
- icdev/tools/security/prompt_injection_detector.py +737 -0
- icdev/tools/security/sast_runner.py +948 -0
- icdev/tools/security/secret_detector.py +378 -0
- icdev/tools/security/tool_chain_validator.py +357 -0
- icdev/tools/security/vuln_scanner.py +539 -0
- icdev/tools/simulation/__init__.py +2 -0
- icdev/tools/simulation/coa_generator.py +1552 -0
- icdev/tools/simulation/monte_carlo.py +758 -0
- icdev/tools/simulation/scenario_manager.py +1073 -0
- icdev/tools/simulation/simulation_engine.py +1104 -0
- icdev/tools/supply_chain/__init__.py +2 -0
- icdev/tools/supply_chain/cve_triager.py +705 -0
- icdev/tools/supply_chain/dependency_graph.py +645 -0
- icdev/tools/supply_chain/isa_manager.py +540 -0
- icdev/tools/supply_chain/scrm_assessor.py +546 -0
- icdev/tools/testing/__init__.py +2 -0
- icdev/tools/testing/acceptance_validator.py +411 -0
- icdev/tools/testing/claude_dir_validator.py +831 -0
- icdev/tools/testing/data_types.py +199 -0
- icdev/tools/testing/e2e_runner.py +715 -0
- icdev/tools/testing/fuzz_cli.py +306 -0
- icdev/tools/testing/health_check.py +483 -0
- icdev/tools/testing/platform_check.py +143 -0
- icdev/tools/testing/production_audit.py +1862 -0
- icdev/tools/testing/production_remediate.py +804 -0
- icdev/tools/testing/screenshot_validator.py +539 -0
- icdev/tools/testing/smoke_test.py +283 -0
- icdev/tools/testing/test_agent_models.py +117 -0
- icdev/tools/testing/test_orchestrator.py +957 -0
- icdev/tools/testing/utils.py +229 -0
- icdev/tools/translation/__init__.py +17 -0
- icdev/tools/translation/code_translator.py +550 -0
- icdev/tools/translation/dependency_mapper.py +277 -0
- icdev/tools/translation/feature_map.py +395 -0
- icdev/tools/translation/project_assembler.py +439 -0
- icdev/tools/translation/source_extractor.py +609 -0
- icdev/tools/translation/test_translator.py +333 -0
- icdev/tools/translation/translation_manager.py +582 -0
- icdev/tools/translation/translation_validator.py +662 -0
- icdev/tools/translation/type_checker.py +371 -0
- icdev-1.0.0.dist-info/METADATA +868 -0
- icdev-1.0.0.dist-info/RECORD +1105 -0
- icdev-1.0.0.dist-info/WHEEL +5 -0
- icdev-1.0.0.dist-info/entry_points.txt +9 -0
- icdev-1.0.0.dist-info/licenses/LICENSE +254 -0
- icdev-1.0.0.dist-info/licenses/NOTICE +268 -0
- icdev-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1658 @@
|
|
|
1
|
+
# [TEMPLATE: CUI // SP-CTI]
|
|
2
|
+
#!/usr/bin/env python3
|
|
3
|
+
"""7R Migration Strategy Recommendation Engine for ICDEV DoD Modernization.
|
|
4
|
+
|
|
5
|
+
Evaluates legacy applications against the 7 Rs of cloud migration:
|
|
6
|
+
Rehost, Replatform, Refactor, Rearchitect, Repurchase, Retire, Retain
|
|
7
|
+
|
|
8
|
+
Reads application profile data from legacy_* tables in icdev.db, scores each
|
|
9
|
+
strategy using configurable weighted criteria, and writes a ranked assessment
|
|
10
|
+
to the migration_assessments table. All scoring is deterministic — no LLM
|
|
11
|
+
calls, no external network access.
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
python tools/modernization/seven_r_assessor.py --project-id P-001 --app-id A-001
|
|
15
|
+
python tools/modernization/seven_r_assessor.py --project-id P-001 --app-id A-001 --matrix
|
|
16
|
+
python tools/modernization/seven_r_assessor.py --project-id P-001 --app-id A-001 --json
|
|
17
|
+
python tools/modernization/seven_r_assessor.py --project-id P-001 --app-id A-001 --weights custom.json
|
|
18
|
+
|
|
19
|
+
Classification: CUI // SP-CTI
|
|
20
|
+
Environment: AWS GovCloud (us-gov-west-1)
|
|
21
|
+
Compliance: NIST 800-53 Rev 5 / RMF
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
import argparse
|
|
25
|
+
import json
|
|
26
|
+
import math
|
|
27
|
+
import sqlite3
|
|
28
|
+
import sys
|
|
29
|
+
import uuid
|
|
30
|
+
from datetime import datetime, timezone
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
from icdev._paths import get_project_root
|
|
33
|
+
|
|
34
|
+
# ---------------------------------------------------------------------------
|
|
35
|
+
# Paths
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
BASE_DIR = get_project_root()
|
|
38
|
+
DB_PATH = BASE_DIR / "data" / "icdev.db"
|
|
39
|
+
CATALOG_PATH = BASE_DIR / "context" / "modernization" / "seven_rs_catalog.json"
|
|
40
|
+
|
|
41
|
+
# ---------------------------------------------------------------------------
|
|
42
|
+
# Known EOL frameworks / languages for fitness checks
|
|
43
|
+
# ---------------------------------------------------------------------------
|
|
44
|
+
EOL_FRAMEWORKS = {
|
|
45
|
+
"struts", "struts2", "ejb2", "jsf", "jsf1",
|
|
46
|
+
"spring2", "spring3",
|
|
47
|
+
"wcf", "webforms", "aspnet-webforms", "silverlight",
|
|
48
|
+
"django1", "flask0",
|
|
49
|
+
"rails3", "rails4",
|
|
50
|
+
"angularjs",
|
|
51
|
+
".net-framework", "dotnet-framework",
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
EOL_LANGUAGES = {
|
|
55
|
+
("python", "2"): True,
|
|
56
|
+
("java", "6"): True,
|
|
57
|
+
("java", "7"): True,
|
|
58
|
+
("ruby", "1"): True,
|
|
59
|
+
("ruby", "2.5"): True,
|
|
60
|
+
("php", "5"): True,
|
|
61
|
+
("php", "7.0"): True,
|
|
62
|
+
("php", "7.1"): True,
|
|
63
|
+
("php", "7.2"): True,
|
|
64
|
+
("php", "7.3"): True,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
# Known version upgrade paths
|
|
68
|
+
KNOWN_UPGRADE_PATHS = {
|
|
69
|
+
("python", "2"): "3",
|
|
70
|
+
("java", "8"): "17",
|
|
71
|
+
("java", "11"): "17",
|
|
72
|
+
("java", "7"): "17",
|
|
73
|
+
("dotnet", "framework-4"): "net-8",
|
|
74
|
+
("csharp", "framework-4"): "net-8",
|
|
75
|
+
("ruby", "2"): "3",
|
|
76
|
+
("php", "7"): "8",
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# Known framework migration paths
|
|
80
|
+
KNOWN_FRAMEWORK_MIGRATIONS = {
|
|
81
|
+
"struts": "spring-boot",
|
|
82
|
+
"struts2": "spring-boot",
|
|
83
|
+
"ejb": "spring-boot",
|
|
84
|
+
"ejb2": "spring-boot",
|
|
85
|
+
"ejb3": "spring-boot",
|
|
86
|
+
"jsf": "spring-boot",
|
|
87
|
+
"wcf": "grpc",
|
|
88
|
+
"webforms": "blazor",
|
|
89
|
+
"aspnet-webforms": "blazor",
|
|
90
|
+
".net-framework": ".net-8",
|
|
91
|
+
"dotnet-framework": ".net-8",
|
|
92
|
+
"django1": "django4",
|
|
93
|
+
"flask0": "flask3",
|
|
94
|
+
"angularjs": "angular",
|
|
95
|
+
"spring3": "spring-boot",
|
|
96
|
+
"spring4": "spring-boot",
|
|
97
|
+
"rails3": "rails7",
|
|
98
|
+
"rails4": "rails7",
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# Standard databases that map well to managed services
|
|
102
|
+
STANDARD_DB_TYPES = {"postgres", "postgresql", "mysql", "mariadb", "aurora"}
|
|
103
|
+
MIGRATABLE_DB_TYPES = {"oracle", "mssql", "sqlserver", "sql-server", "db2"}
|
|
104
|
+
EXOTIC_DB_TYPES = {"informix", "sybase", "ingres", "pick", "mumps", "adabas"}
|
|
105
|
+
|
|
106
|
+
# Risk level numeric mapping
|
|
107
|
+
RISK_LEVEL_MAP = {
|
|
108
|
+
"none": 0.0,
|
|
109
|
+
"low": 0.2,
|
|
110
|
+
"medium": 0.5,
|
|
111
|
+
"high": 0.8,
|
|
112
|
+
"critical": 1.0,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# ATO impact ordering for display
|
|
116
|
+
ATO_IMPACT_ORDER = {
|
|
117
|
+
"none": 0,
|
|
118
|
+
"low": 1,
|
|
119
|
+
"medium": 2,
|
|
120
|
+
"high": 3,
|
|
121
|
+
"critical": 4,
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# ============================================================================
|
|
126
|
+
# Database helper
|
|
127
|
+
# ============================================================================
|
|
128
|
+
|
|
129
|
+
def _get_db(db_path=None):
|
|
130
|
+
"""Return a sqlite3 connection with Row factory for dict-like access.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
db_path: Optional override path to the SQLite database.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
sqlite3.Connection with row_factory set to sqlite3.Row.
|
|
137
|
+
|
|
138
|
+
Raises:
|
|
139
|
+
FileNotFoundError: If the database file does not exist.
|
|
140
|
+
"""
|
|
141
|
+
path = db_path or DB_PATH
|
|
142
|
+
if not path.exists():
|
|
143
|
+
raise FileNotFoundError(
|
|
144
|
+
f"Database not found: {path}\n"
|
|
145
|
+
"Run: python tools/db/init_icdev_db.py"
|
|
146
|
+
)
|
|
147
|
+
conn = sqlite3.connect(str(path))
|
|
148
|
+
conn.row_factory = sqlite3.Row
|
|
149
|
+
return conn
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# ============================================================================
|
|
153
|
+
# Catalog loader
|
|
154
|
+
# ============================================================================
|
|
155
|
+
|
|
156
|
+
def load_seven_rs_catalog(catalog_path=None):
|
|
157
|
+
"""Load the 7 Rs strategy catalog from JSON.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
catalog_path: Optional override path to the catalog JSON file.
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
Parsed dict containing metadata, default_weights, and strategies list.
|
|
164
|
+
|
|
165
|
+
Raises:
|
|
166
|
+
FileNotFoundError: If the catalog file does not exist.
|
|
167
|
+
json.JSONDecodeError: If the catalog contains invalid JSON.
|
|
168
|
+
"""
|
|
169
|
+
path = catalog_path or CATALOG_PATH
|
|
170
|
+
if not path.exists():
|
|
171
|
+
raise FileNotFoundError(
|
|
172
|
+
f"Seven Rs catalog not found: {path}\n"
|
|
173
|
+
"Expected at: context/modernization/seven_rs_catalog.json"
|
|
174
|
+
)
|
|
175
|
+
with open(path, "r", encoding="utf-8") as fh:
|
|
176
|
+
catalog = json.load(fh)
|
|
177
|
+
return catalog
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
# ============================================================================
|
|
181
|
+
# Application profile builder
|
|
182
|
+
# ============================================================================
|
|
183
|
+
|
|
184
|
+
def _get_app_profile(app_id, db_path=None):
|
|
185
|
+
"""Query legacy_applications and aggregate stats from related tables.
|
|
186
|
+
|
|
187
|
+
Builds a comprehensive profile dict containing:
|
|
188
|
+
- All columns from legacy_applications
|
|
189
|
+
- Aggregated component statistics (count, avg complexity, avg coupling, etc.)
|
|
190
|
+
- Dependency counts by type
|
|
191
|
+
- API count
|
|
192
|
+
- Database schema information
|
|
193
|
+
- Derived metrics (test ratio, package count, etc.)
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
app_id: The legacy application ID to look up.
|
|
197
|
+
db_path: Optional database path override.
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
Dict with all metrics needed for scoring.
|
|
201
|
+
|
|
202
|
+
Raises:
|
|
203
|
+
ValueError: If the application ID is not found in the database.
|
|
204
|
+
"""
|
|
205
|
+
conn = _get_db(db_path)
|
|
206
|
+
try:
|
|
207
|
+
# --- Core application row ---
|
|
208
|
+
row = conn.execute(
|
|
209
|
+
"SELECT * FROM legacy_applications WHERE id = ?", (app_id,)
|
|
210
|
+
).fetchone()
|
|
211
|
+
if row is None:
|
|
212
|
+
raise ValueError(
|
|
213
|
+
f"Application '{app_id}' not found in legacy_applications."
|
|
214
|
+
)
|
|
215
|
+
profile = dict(row)
|
|
216
|
+
|
|
217
|
+
# --- Component aggregates ---
|
|
218
|
+
comp_rows = conn.execute(
|
|
219
|
+
"SELECT * FROM legacy_components WHERE legacy_app_id = ?",
|
|
220
|
+
(app_id,),
|
|
221
|
+
).fetchall()
|
|
222
|
+
|
|
223
|
+
components = [dict(r) for r in comp_rows]
|
|
224
|
+
profile["components"] = components
|
|
225
|
+
profile["component_count"] = len(components)
|
|
226
|
+
|
|
227
|
+
if components:
|
|
228
|
+
complexities = [c.get("cyclomatic_complexity", 0) or 0 for c in components]
|
|
229
|
+
couplings = [c.get("coupling_score", 0) or 0 for c in components]
|
|
230
|
+
cohesions = [c.get("cohesion_score", 0) or 0 for c in components]
|
|
231
|
+
deps_in = [c.get("dependencies_in", 0) or 0 for c in components]
|
|
232
|
+
deps_out = [c.get("dependencies_out", 0) or 0 for c in components]
|
|
233
|
+
locs = [c.get("loc", 0) or 0 for c in components]
|
|
234
|
+
types = [c.get("component_type", "") for c in components]
|
|
235
|
+
|
|
236
|
+
profile["avg_complexity"] = sum(complexities) / len(complexities)
|
|
237
|
+
profile["max_complexity"] = max(complexities)
|
|
238
|
+
profile["avg_coupling"] = sum(couplings) / len(couplings)
|
|
239
|
+
profile["avg_cohesion"] = sum(cohesions) / len(cohesions)
|
|
240
|
+
profile["total_deps_in"] = sum(deps_in)
|
|
241
|
+
profile["total_deps_out"] = sum(deps_out)
|
|
242
|
+
profile["total_component_loc"] = sum(locs)
|
|
243
|
+
profile["component_types"] = list(set(types))
|
|
244
|
+
|
|
245
|
+
# Count test-related components
|
|
246
|
+
test_types = {"test", "tests", "test_suite", "unit_test", "integration_test", "spec"}
|
|
247
|
+
test_count = sum(1 for t in types if t and t.lower() in test_types)
|
|
248
|
+
profile["test_component_count"] = test_count
|
|
249
|
+
profile["test_component_ratio"] = test_count / len(components) if components else 0.0
|
|
250
|
+
|
|
251
|
+
# Count distinct packages / namespaces
|
|
252
|
+
namespaces = set()
|
|
253
|
+
for c in components:
|
|
254
|
+
ctype = (c.get("component_type") or "").lower()
|
|
255
|
+
if ctype in ("package", "namespace", "module"):
|
|
256
|
+
namespaces.add(c.get("id"))
|
|
257
|
+
profile["distinct_namespaces"] = len(namespaces) if namespaces else max(1, len(set(types)))
|
|
258
|
+
else:
|
|
259
|
+
profile["avg_complexity"] = 0
|
|
260
|
+
profile["max_complexity"] = 0
|
|
261
|
+
profile["avg_coupling"] = 0
|
|
262
|
+
profile["avg_cohesion"] = 0
|
|
263
|
+
profile["total_deps_in"] = 0
|
|
264
|
+
profile["total_deps_out"] = 0
|
|
265
|
+
profile["total_component_loc"] = 0
|
|
266
|
+
profile["component_types"] = []
|
|
267
|
+
profile["test_component_count"] = 0
|
|
268
|
+
profile["test_component_ratio"] = 0.0
|
|
269
|
+
profile["distinct_namespaces"] = 0
|
|
270
|
+
|
|
271
|
+
# --- Dependency aggregates ---
|
|
272
|
+
dep_rows = conn.execute(
|
|
273
|
+
"SELECT * FROM legacy_dependencies WHERE legacy_app_id = ?",
|
|
274
|
+
(app_id,),
|
|
275
|
+
).fetchall()
|
|
276
|
+
dependencies = [dict(r) for r in dep_rows]
|
|
277
|
+
profile["dependencies"] = dependencies
|
|
278
|
+
profile["dependency_count"] = len(dependencies)
|
|
279
|
+
|
|
280
|
+
dep_type_counts = {}
|
|
281
|
+
for d in dependencies:
|
|
282
|
+
dtype = d.get("dependency_type", "unknown")
|
|
283
|
+
dep_type_counts[dtype] = dep_type_counts.get(dtype, 0) + 1
|
|
284
|
+
profile["dependency_type_counts"] = dep_type_counts
|
|
285
|
+
profile["external_dep_count"] = dep_type_counts.get("external", 0) + dep_type_counts.get("third_party", 0) + dep_type_counts.get("library", 0)
|
|
286
|
+
|
|
287
|
+
# --- API aggregates ---
|
|
288
|
+
api_rows = conn.execute(
|
|
289
|
+
"SELECT * FROM legacy_apis WHERE legacy_app_id = ?",
|
|
290
|
+
(app_id,),
|
|
291
|
+
).fetchall()
|
|
292
|
+
profile["apis"] = [dict(r) for r in api_rows]
|
|
293
|
+
profile["api_count"] = len(api_rows)
|
|
294
|
+
|
|
295
|
+
# --- DB schema aggregates ---
|
|
296
|
+
db_rows = conn.execute(
|
|
297
|
+
"SELECT * FROM legacy_db_schemas WHERE legacy_app_id = ?",
|
|
298
|
+
(app_id,),
|
|
299
|
+
).fetchall()
|
|
300
|
+
db_schemas = [dict(r) for r in db_rows]
|
|
301
|
+
profile["db_schemas"] = db_schemas
|
|
302
|
+
profile["db_schema_count"] = len(db_schemas)
|
|
303
|
+
profile["db_types"] = list(set(
|
|
304
|
+
(s.get("db_type") or "unknown").lower() for s in db_schemas
|
|
305
|
+
))
|
|
306
|
+
|
|
307
|
+
# --- Normalize key fields with safe defaults ---
|
|
308
|
+
profile["loc_total"] = profile.get("loc_total") or 0
|
|
309
|
+
profile["loc_code"] = profile.get("loc_code") or 0
|
|
310
|
+
profile["file_count"] = profile.get("file_count") or 0
|
|
311
|
+
profile["complexity_score"] = profile.get("complexity_score") or 0.0
|
|
312
|
+
profile["tech_debt_hours"] = profile.get("tech_debt_hours") or 0.0
|
|
313
|
+
profile["maintainability_index"] = profile.get("maintainability_index") or 0.0
|
|
314
|
+
profile["primary_language"] = (profile.get("primary_language") or "unknown").lower()
|
|
315
|
+
profile["language_version"] = (profile.get("language_version") or "").lower()
|
|
316
|
+
profile["framework"] = (profile.get("framework") or "unknown").lower()
|
|
317
|
+
profile["framework_version"] = (profile.get("framework_version") or "").lower()
|
|
318
|
+
profile["app_type"] = (profile.get("app_type") or "unknown").lower()
|
|
319
|
+
|
|
320
|
+
return profile
|
|
321
|
+
finally:
|
|
322
|
+
conn.close()
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
# ============================================================================
|
|
326
|
+
# Fitness check functions — one per strategy
|
|
327
|
+
# ============================================================================
|
|
328
|
+
|
|
329
|
+
def _check_rehost_fitness(profile):
|
|
330
|
+
"""Evaluate rehost (lift-and-shift) fitness.
|
|
331
|
+
|
|
332
|
+
Criteria:
|
|
333
|
+
containerizable — minimal OS/file-system coupling
|
|
334
|
+
external_deps_minimal — few external dependencies
|
|
335
|
+
config_externalizable — config separate from code
|
|
336
|
+
stateless — no heavy local state / file writes
|
|
337
|
+
security_clean — good maintainability, low complexity
|
|
338
|
+
|
|
339
|
+
Returns:
|
|
340
|
+
Dict mapping criterion name to float score in [0.0, 1.0].
|
|
341
|
+
"""
|
|
342
|
+
scores = {}
|
|
343
|
+
|
|
344
|
+
# containerizable: heuristic based on dependency types
|
|
345
|
+
os_dep_keywords = {"os-specific", "hardware", "native", "driver", "kernel", "system"}
|
|
346
|
+
file_dep_keywords = {"file-io", "local-storage", "nfs", "smb", "cifs", "shared-drive"}
|
|
347
|
+
|
|
348
|
+
os_count = 0
|
|
349
|
+
file_count = 0
|
|
350
|
+
for d in profile.get("dependencies", []):
|
|
351
|
+
dtype = (d.get("dependency_type") or "").lower()
|
|
352
|
+
if any(k in dtype for k in os_dep_keywords):
|
|
353
|
+
os_count += 1
|
|
354
|
+
if any(k in dtype for k in file_dep_keywords):
|
|
355
|
+
file_count += 1
|
|
356
|
+
|
|
357
|
+
heavy_count = os_count + file_count
|
|
358
|
+
if heavy_count == 0:
|
|
359
|
+
scores["containerizable"] = 1.0
|
|
360
|
+
elif heavy_count <= 3:
|
|
361
|
+
scores["containerizable"] = 0.5
|
|
362
|
+
else:
|
|
363
|
+
scores["containerizable"] = 0.0
|
|
364
|
+
|
|
365
|
+
# external_deps_minimal
|
|
366
|
+
ext_count = profile.get("external_dep_count", 0)
|
|
367
|
+
if ext_count < 5:
|
|
368
|
+
scores["external_deps_minimal"] = 1.0
|
|
369
|
+
elif ext_count <= 15:
|
|
370
|
+
scores["external_deps_minimal"] = 0.5
|
|
371
|
+
else:
|
|
372
|
+
scores["external_deps_minimal"] = 0.0
|
|
373
|
+
|
|
374
|
+
# config_externalizable: heuristic — if file_count > 0 and complexity is
|
|
375
|
+
# low, config is likely separable. We use a proxy: maintainability > 50
|
|
376
|
+
# and low coupling suggest well-structured config.
|
|
377
|
+
maint = profile.get("maintainability_index", 0)
|
|
378
|
+
coupling = profile.get("avg_coupling", 0)
|
|
379
|
+
if maint > 50 and coupling < 0.5:
|
|
380
|
+
scores["config_externalizable"] = 1.0
|
|
381
|
+
elif maint > 30 or coupling < 0.7:
|
|
382
|
+
scores["config_externalizable"] = 0.5
|
|
383
|
+
else:
|
|
384
|
+
scores["config_externalizable"] = 0.0
|
|
385
|
+
|
|
386
|
+
# stateless: check for local-file write type dependencies
|
|
387
|
+
write_keywords = {"file-write", "local-write", "local-storage", "tmp-storage", "session-file"}
|
|
388
|
+
write_count = 0
|
|
389
|
+
for d in profile.get("dependencies", []):
|
|
390
|
+
dtype = (d.get("dependency_type") or "").lower()
|
|
391
|
+
if any(k in dtype for k in write_keywords):
|
|
392
|
+
write_count += 1
|
|
393
|
+
if write_count == 0:
|
|
394
|
+
scores["stateless"] = 1.0
|
|
395
|
+
elif write_count <= 2:
|
|
396
|
+
scores["stateless"] = 0.5
|
|
397
|
+
else:
|
|
398
|
+
scores["stateless"] = 0.0
|
|
399
|
+
|
|
400
|
+
# security_clean: maintainability > 60 AND avg complexity < 15
|
|
401
|
+
avg_cx = profile.get("avg_complexity", 0)
|
|
402
|
+
if maint > 60 and avg_cx < 15:
|
|
403
|
+
scores["security_clean"] = 1.0
|
|
404
|
+
elif maint > 40 and avg_cx < 25:
|
|
405
|
+
scores["security_clean"] = 0.5
|
|
406
|
+
else:
|
|
407
|
+
scores["security_clean"] = 0.0
|
|
408
|
+
|
|
409
|
+
return scores
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def _check_replatform_fitness(profile):
|
|
413
|
+
"""Evaluate replatform (lift-tinker-shift) fitness.
|
|
414
|
+
|
|
415
|
+
Criteria:
|
|
416
|
+
managed_db_candidate — database can move to managed service
|
|
417
|
+
container_ready_with_tweaks — mostly containerizable
|
|
418
|
+
config_separable — config extractable to env vars
|
|
419
|
+
cloud_services_available — standard service replacements exist
|
|
420
|
+
minor_code_changes_only — less than 10% code needs changes
|
|
421
|
+
|
|
422
|
+
Returns:
|
|
423
|
+
Dict mapping criterion name to float score in [0.0, 1.0].
|
|
424
|
+
"""
|
|
425
|
+
scores = {}
|
|
426
|
+
|
|
427
|
+
# managed_db_candidate
|
|
428
|
+
db_types = set(profile.get("db_types", []))
|
|
429
|
+
if not db_types or db_types <= STANDARD_DB_TYPES:
|
|
430
|
+
scores["managed_db_candidate"] = 1.0
|
|
431
|
+
elif db_types & MIGRATABLE_DB_TYPES:
|
|
432
|
+
scores["managed_db_candidate"] = 0.5
|
|
433
|
+
elif db_types & EXOTIC_DB_TYPES:
|
|
434
|
+
scores["managed_db_candidate"] = 0.0
|
|
435
|
+
else:
|
|
436
|
+
# Unknown DB type — conservative score
|
|
437
|
+
scores["managed_db_candidate"] = 0.5
|
|
438
|
+
|
|
439
|
+
# container_ready_with_tweaks: reuse containerizable from rehost, but
|
|
440
|
+
# accept slightly worse scores.
|
|
441
|
+
rehost_fit = _check_rehost_fitness(profile)
|
|
442
|
+
container_score = rehost_fit.get("containerizable", 0.0)
|
|
443
|
+
if container_score >= 0.5:
|
|
444
|
+
scores["container_ready_with_tweaks"] = 1.0
|
|
445
|
+
elif container_score > 0.0:
|
|
446
|
+
scores["container_ready_with_tweaks"] = 0.5
|
|
447
|
+
else:
|
|
448
|
+
scores["container_ready_with_tweaks"] = 0.0
|
|
449
|
+
|
|
450
|
+
# config_separable
|
|
451
|
+
maint = profile.get("maintainability_index", 0)
|
|
452
|
+
coupling = profile.get("avg_coupling", 0)
|
|
453
|
+
if maint > 40 and coupling < 0.6:
|
|
454
|
+
scores["config_separable"] = 1.0
|
|
455
|
+
elif maint > 25 or coupling < 0.8:
|
|
456
|
+
scores["config_separable"] = 0.5
|
|
457
|
+
else:
|
|
458
|
+
scores["config_separable"] = 0.0
|
|
459
|
+
|
|
460
|
+
# cloud_services_available: standard app types have good cloud equivalents
|
|
461
|
+
app_type = profile.get("app_type", "unknown")
|
|
462
|
+
standard_app_types = {"web", "api", "microservice", "batch", "worker", "queue-consumer", "rest-api"}
|
|
463
|
+
custom_app_types = {"desktop", "embedded", "hardware-interface", "mainframe"}
|
|
464
|
+
if app_type in standard_app_types:
|
|
465
|
+
scores["cloud_services_available"] = 1.0
|
|
466
|
+
elif app_type in custom_app_types:
|
|
467
|
+
scores["cloud_services_available"] = 0.0
|
|
468
|
+
else:
|
|
469
|
+
scores["cloud_services_available"] = 0.5
|
|
470
|
+
|
|
471
|
+
# minor_code_changes_only: low tech debt + good maintainability means
|
|
472
|
+
# changes should be small
|
|
473
|
+
loc_total = profile.get("loc_total", 1)
|
|
474
|
+
tech_debt = profile.get("tech_debt_hours", 0)
|
|
475
|
+
# Rough heuristic: tech_debt_hours / (loc_total/100) gives a debt density
|
|
476
|
+
debt_density = (tech_debt / max(loc_total / 100.0, 1.0))
|
|
477
|
+
if debt_density < 5 and maint > 50:
|
|
478
|
+
scores["minor_code_changes_only"] = 1.0
|
|
479
|
+
elif debt_density < 15 and maint > 30:
|
|
480
|
+
scores["minor_code_changes_only"] = 0.5
|
|
481
|
+
else:
|
|
482
|
+
scores["minor_code_changes_only"] = 0.0
|
|
483
|
+
|
|
484
|
+
return scores
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
def _check_refactor_fitness(profile):
|
|
488
|
+
"""Evaluate refactor (code-level modernization) fitness.
|
|
489
|
+
|
|
490
|
+
Criteria:
|
|
491
|
+
version_upgrade_path_exists — known upgrade path for language
|
|
492
|
+
framework_migration_path_exists — known migration for framework
|
|
493
|
+
test_coverage_adequate — sufficient test components
|
|
494
|
+
codebase_well_structured — maintainability index
|
|
495
|
+
dependencies_manageable — component count not overwhelming
|
|
496
|
+
|
|
497
|
+
Returns:
|
|
498
|
+
Dict mapping criterion name to float score in [0.0, 1.0].
|
|
499
|
+
"""
|
|
500
|
+
scores = {}
|
|
501
|
+
|
|
502
|
+
# version_upgrade_path_exists
|
|
503
|
+
lang = profile.get("primary_language", "")
|
|
504
|
+
lang_ver = profile.get("language_version", "")
|
|
505
|
+
# Normalize: take just the major version for matching
|
|
506
|
+
lang_ver_major = lang_ver.split(".")[0] if lang_ver else ""
|
|
507
|
+
key = (lang, lang_ver_major)
|
|
508
|
+
if key in KNOWN_UPGRADE_PATHS:
|
|
509
|
+
scores["version_upgrade_path_exists"] = 1.0
|
|
510
|
+
elif lang_ver:
|
|
511
|
+
# Version specified but no known path — partial credit
|
|
512
|
+
scores["version_upgrade_path_exists"] = 0.3
|
|
513
|
+
else:
|
|
514
|
+
scores["version_upgrade_path_exists"] = 0.0
|
|
515
|
+
|
|
516
|
+
# framework_migration_path_exists
|
|
517
|
+
framework = profile.get("framework", "").lower().strip()
|
|
518
|
+
framework_normalized = framework.replace(" ", "-").replace("_", "-")
|
|
519
|
+
if framework_normalized in KNOWN_FRAMEWORK_MIGRATIONS:
|
|
520
|
+
scores["framework_migration_path_exists"] = 1.0
|
|
521
|
+
elif framework and framework != "unknown":
|
|
522
|
+
scores["framework_migration_path_exists"] = 0.3
|
|
523
|
+
else:
|
|
524
|
+
scores["framework_migration_path_exists"] = 0.0
|
|
525
|
+
|
|
526
|
+
# test_coverage_adequate: >20% test components is good, some is partial
|
|
527
|
+
test_ratio = profile.get("test_component_ratio", 0.0)
|
|
528
|
+
if test_ratio >= 0.20:
|
|
529
|
+
scores["test_coverage_adequate"] = 1.0
|
|
530
|
+
elif test_ratio > 0.0:
|
|
531
|
+
scores["test_coverage_adequate"] = 0.5
|
|
532
|
+
else:
|
|
533
|
+
scores["test_coverage_adequate"] = 0.0
|
|
534
|
+
|
|
535
|
+
# codebase_well_structured: maintainability index
|
|
536
|
+
maint = profile.get("maintainability_index", 0)
|
|
537
|
+
if maint > 50:
|
|
538
|
+
scores["codebase_well_structured"] = 1.0
|
|
539
|
+
elif maint >= 25:
|
|
540
|
+
scores["codebase_well_structured"] = 0.5
|
|
541
|
+
else:
|
|
542
|
+
scores["codebase_well_structured"] = 0.0
|
|
543
|
+
|
|
544
|
+
# dependencies_manageable: component count
|
|
545
|
+
comp_count = profile.get("component_count", 0)
|
|
546
|
+
if comp_count < 50:
|
|
547
|
+
scores["dependencies_manageable"] = 1.0
|
|
548
|
+
elif comp_count <= 200:
|
|
549
|
+
scores["dependencies_manageable"] = 0.5
|
|
550
|
+
else:
|
|
551
|
+
scores["dependencies_manageable"] = 0.0
|
|
552
|
+
|
|
553
|
+
return scores
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
def _check_rearchitect_fitness(profile):
|
|
557
|
+
"""Evaluate rearchitect (rebuild cloud-native) fitness.
|
|
558
|
+
|
|
559
|
+
Criteria:
|
|
560
|
+
bounded_contexts_identifiable — distinct packages with low coupling
|
|
561
|
+
api_boundaries_clear — well-defined API endpoints
|
|
562
|
+
data_stores_separable — database schemas cluster
|
|
563
|
+
team_capacity_sufficient — default 0.5 (needs manual input)
|
|
564
|
+
business_value_high — default 0.5 (needs manual input)
|
|
565
|
+
|
|
566
|
+
Returns:
|
|
567
|
+
Dict mapping criterion name to float score in [0.0, 1.0].
|
|
568
|
+
"""
|
|
569
|
+
scores = {}
|
|
570
|
+
|
|
571
|
+
# bounded_contexts_identifiable: >3 namespaces with avg_coupling < 0.5
|
|
572
|
+
namespaces = profile.get("distinct_namespaces", 0)
|
|
573
|
+
avg_coupling = profile.get("avg_coupling", 1.0)
|
|
574
|
+
if namespaces > 3 and avg_coupling < 0.5:
|
|
575
|
+
scores["bounded_contexts_identifiable"] = 1.0
|
|
576
|
+
elif namespaces > 2 and avg_coupling < 0.7:
|
|
577
|
+
scores["bounded_contexts_identifiable"] = 0.5
|
|
578
|
+
else:
|
|
579
|
+
scores["bounded_contexts_identifiable"] = 0.0
|
|
580
|
+
|
|
581
|
+
# api_boundaries_clear: >5 API endpoints suggest clear grouping
|
|
582
|
+
api_count = profile.get("api_count", 0)
|
|
583
|
+
if api_count >= 5:
|
|
584
|
+
scores["api_boundaries_clear"] = 1.0
|
|
585
|
+
elif api_count >= 2:
|
|
586
|
+
scores["api_boundaries_clear"] = 0.5
|
|
587
|
+
else:
|
|
588
|
+
scores["api_boundaries_clear"] = 0.0
|
|
589
|
+
|
|
590
|
+
# data_stores_separable: multiple DB schemas suggest separable data
|
|
591
|
+
db_count = profile.get("db_schema_count", 0)
|
|
592
|
+
if db_count >= 3:
|
|
593
|
+
scores["data_stores_separable"] = 1.0
|
|
594
|
+
elif db_count >= 2:
|
|
595
|
+
scores["data_stores_separable"] = 0.5
|
|
596
|
+
else:
|
|
597
|
+
scores["data_stores_separable"] = 0.0
|
|
598
|
+
|
|
599
|
+
# team_capacity_sufficient: requires manual assessment, default 0.5
|
|
600
|
+
scores["team_capacity_sufficient"] = 0.5
|
|
601
|
+
|
|
602
|
+
# business_value_high: requires manual assessment, default 0.5
|
|
603
|
+
scores["business_value_high"] = 0.5
|
|
604
|
+
|
|
605
|
+
return scores
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
def _check_repurchase_fitness(profile):
|
|
609
|
+
"""Evaluate repurchase (buy COTS/GOTS replacement) fitness.
|
|
610
|
+
|
|
611
|
+
Criteria:
|
|
612
|
+
commodity_functionality — is it a common business function (default)
|
|
613
|
+
cots_alternative_available — needs manual assessment (default)
|
|
614
|
+
low_customization — LOC indicates customization level
|
|
615
|
+
data_migration_feasible — default, needs manual assessment
|
|
616
|
+
|
|
617
|
+
Returns:
|
|
618
|
+
Dict mapping criterion name to float score in [0.0, 1.0].
|
|
619
|
+
"""
|
|
620
|
+
scores = {}
|
|
621
|
+
|
|
622
|
+
# commodity_functionality: default — needs manual assessment
|
|
623
|
+
scores["commodity_functionality"] = 0.5
|
|
624
|
+
|
|
625
|
+
# cots_alternative_available: default — needs manual assessment
|
|
626
|
+
scores["cots_alternative_available"] = 0.5
|
|
627
|
+
|
|
628
|
+
# low_customization: based on LOC
|
|
629
|
+
loc = profile.get("loc_code", 0) or profile.get("loc_total", 0)
|
|
630
|
+
if loc < 5000:
|
|
631
|
+
scores["low_customization"] = 1.0
|
|
632
|
+
elif loc <= 20000:
|
|
633
|
+
scores["low_customization"] = 0.5
|
|
634
|
+
else:
|
|
635
|
+
scores["low_customization"] = 0.0
|
|
636
|
+
|
|
637
|
+
# data_migration_feasible: default — needs manual assessment
|
|
638
|
+
scores["data_migration_feasible"] = 0.5
|
|
639
|
+
|
|
640
|
+
return scores
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
def _check_retire_fitness(profile):
|
|
644
|
+
"""Evaluate retire (decommission) fitness.
|
|
645
|
+
|
|
646
|
+
Criteria:
|
|
647
|
+
low_usage — default 0.5 (needs usage data)
|
|
648
|
+
redundant_functionality — default 0.5
|
|
649
|
+
eol_dependencies — framework/language at end-of-life
|
|
650
|
+
no_active_development — default 0.5
|
|
651
|
+
|
|
652
|
+
Returns:
|
|
653
|
+
Dict mapping criterion name to float score in [0.0, 1.0].
|
|
654
|
+
"""
|
|
655
|
+
scores = {}
|
|
656
|
+
|
|
657
|
+
# low_usage: requires usage telemetry, default 0.5
|
|
658
|
+
scores["low_usage"] = 0.5
|
|
659
|
+
|
|
660
|
+
# redundant_functionality: default 0.5
|
|
661
|
+
scores["redundant_functionality"] = 0.5
|
|
662
|
+
|
|
663
|
+
# eol_dependencies: check if framework or language version is EOL
|
|
664
|
+
framework = profile.get("framework", "").lower().strip().replace(" ", "-").replace("_", "-")
|
|
665
|
+
lang = profile.get("primary_language", "")
|
|
666
|
+
lang_ver = profile.get("language_version", "")
|
|
667
|
+
lang_ver_major = lang_ver.split(".")[0] if lang_ver else ""
|
|
668
|
+
|
|
669
|
+
is_eol = False
|
|
670
|
+
if framework in EOL_FRAMEWORKS:
|
|
671
|
+
is_eol = True
|
|
672
|
+
if (lang, lang_ver_major) in EOL_LANGUAGES:
|
|
673
|
+
is_eol = True
|
|
674
|
+
# Also check framework + major version combos
|
|
675
|
+
if framework and not is_eol:
|
|
676
|
+
fw_ver = profile.get("framework_version", "")
|
|
677
|
+
fw_ver_major = fw_ver.split(".")[0] if fw_ver else ""
|
|
678
|
+
combined = f"{framework}{fw_ver_major}"
|
|
679
|
+
if combined in EOL_FRAMEWORKS:
|
|
680
|
+
is_eol = True
|
|
681
|
+
|
|
682
|
+
scores["eol_dependencies"] = 1.0 if is_eol else 0.0
|
|
683
|
+
|
|
684
|
+
# no_active_development: default 0.5
|
|
685
|
+
scores["no_active_development"] = 0.5
|
|
686
|
+
|
|
687
|
+
return scores
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
def _check_retain_fitness(profile):
|
|
691
|
+
"""Evaluate retain (keep in place) fitness.
|
|
692
|
+
|
|
693
|
+
Criteria:
|
|
694
|
+
stable_operation — low complexity and good maintainability
|
|
695
|
+
no_ato_blockers — maintainability > 40 and complexity < 20
|
|
696
|
+
low_risk — tech debt hours < 100
|
|
697
|
+
recent_framework — framework is not EOL
|
|
698
|
+
|
|
699
|
+
Returns:
|
|
700
|
+
Dict mapping criterion name to float score in [0.0, 1.0].
|
|
701
|
+
"""
|
|
702
|
+
scores = {}
|
|
703
|
+
|
|
704
|
+
maint = profile.get("maintainability_index", 0)
|
|
705
|
+
avg_cx = profile.get("avg_complexity", 0)
|
|
706
|
+
tech_debt = profile.get("tech_debt_hours", 0)
|
|
707
|
+
|
|
708
|
+
# stable_operation: low complexity and good maintainability
|
|
709
|
+
if avg_cx < 10 and maint > 60:
|
|
710
|
+
scores["stable_operation"] = 1.0
|
|
711
|
+
elif avg_cx < 20 and maint > 40:
|
|
712
|
+
scores["stable_operation"] = 0.5
|
|
713
|
+
else:
|
|
714
|
+
scores["stable_operation"] = 0.0
|
|
715
|
+
|
|
716
|
+
# no_ato_blockers: maintainability > 40 and complexity < 20
|
|
717
|
+
if maint > 40 and avg_cx < 20:
|
|
718
|
+
scores["no_ato_blockers"] = 1.0
|
|
719
|
+
elif maint > 25 and avg_cx < 30:
|
|
720
|
+
scores["no_ato_blockers"] = 0.5
|
|
721
|
+
else:
|
|
722
|
+
scores["no_ato_blockers"] = 0.0
|
|
723
|
+
|
|
724
|
+
# low_risk: tech_debt_hours < 100
|
|
725
|
+
if tech_debt < 100:
|
|
726
|
+
scores["low_risk"] = 1.0
|
|
727
|
+
elif tech_debt < 500:
|
|
728
|
+
scores["low_risk"] = 0.5
|
|
729
|
+
else:
|
|
730
|
+
scores["low_risk"] = 0.0
|
|
731
|
+
|
|
732
|
+
# recent_framework: framework is NOT EOL
|
|
733
|
+
framework = profile.get("framework", "").lower().strip().replace(" ", "-").replace("_", "-")
|
|
734
|
+
lang = profile.get("primary_language", "")
|
|
735
|
+
lang_ver = profile.get("language_version", "")
|
|
736
|
+
lang_ver_major = lang_ver.split(".")[0] if lang_ver else ""
|
|
737
|
+
|
|
738
|
+
is_eol = False
|
|
739
|
+
if framework in EOL_FRAMEWORKS:
|
|
740
|
+
is_eol = True
|
|
741
|
+
if (lang, lang_ver_major) in EOL_LANGUAGES:
|
|
742
|
+
is_eol = True
|
|
743
|
+
|
|
744
|
+
scores["recent_framework"] = 0.0 if is_eol else 1.0
|
|
745
|
+
|
|
746
|
+
return scores
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
# ============================================================================
|
|
750
|
+
# Scoring engine
|
|
751
|
+
# ============================================================================
|
|
752
|
+
|
|
753
|
+
def _score_strategy(strategy_id, check_results, catalog_criteria, weights=None):
|
|
754
|
+
"""Compute weighted score for a single strategy.
|
|
755
|
+
|
|
756
|
+
For each criterion in the catalog, multiply the check_result by the
|
|
757
|
+
criterion's weight. Sum all weighted scores. Apply the strategy's
|
|
758
|
+
effort_multiplier as a penalty (higher effort = lower attractiveness).
|
|
759
|
+
|
|
760
|
+
The raw weighted sum is in [0.0, 1.0] because criterion weights sum to
|
|
761
|
+
~1.0 and check results are in [0.0, 1.0]. The effort penalty adjusts
|
|
762
|
+
the final score to favour lower-effort strategies when fitness is equal.
|
|
763
|
+
|
|
764
|
+
Args:
|
|
765
|
+
strategy_id: The strategy identifier (e.g. "rehost").
|
|
766
|
+
check_results: Dict of {criterion_name: score} from _check_*_fitness.
|
|
767
|
+
catalog_criteria: Dict of {criterion_name: {weight, description}} from
|
|
768
|
+
the catalog's scoring_criteria for this strategy.
|
|
769
|
+
weights: Optional dict of custom criterion weights to override
|
|
770
|
+
catalog defaults.
|
|
771
|
+
|
|
772
|
+
Returns:
|
|
773
|
+
Float score in [0.0, 1.0] (normalized).
|
|
774
|
+
"""
|
|
775
|
+
if not catalog_criteria:
|
|
776
|
+
return 0.0
|
|
777
|
+
|
|
778
|
+
# Build effective weights: start with catalog, override with custom
|
|
779
|
+
effective_weights = {}
|
|
780
|
+
for crit_name, crit_info in catalog_criteria.items():
|
|
781
|
+
effective_weights[crit_name] = crit_info.get("weight", 0.0)
|
|
782
|
+
|
|
783
|
+
if weights and strategy_id in weights:
|
|
784
|
+
for crit_name, w in weights[strategy_id].items():
|
|
785
|
+
if crit_name in effective_weights:
|
|
786
|
+
effective_weights[crit_name] = w
|
|
787
|
+
|
|
788
|
+
# Calculate weighted sum. For catalog criteria that have no matching
|
|
789
|
+
# check_result key, we map by positional order (catalog criterion → check
|
|
790
|
+
# result) to bridge the gap between catalog criterion names and the
|
|
791
|
+
# check function criterion names.
|
|
792
|
+
catalog_crit_names = list(catalog_criteria.keys())
|
|
793
|
+
check_crit_names = list(check_results.keys())
|
|
794
|
+
|
|
795
|
+
weighted_sum = 0.0
|
|
796
|
+
total_weight = 0.0
|
|
797
|
+
|
|
798
|
+
for i, cat_crit in enumerate(catalog_crit_names):
|
|
799
|
+
weight = effective_weights.get(cat_crit, 0.0)
|
|
800
|
+
# Direct name match first
|
|
801
|
+
if cat_crit in check_results:
|
|
802
|
+
score = check_results[cat_crit]
|
|
803
|
+
elif i < len(check_crit_names):
|
|
804
|
+
# Positional fallback: map i-th catalog criterion to i-th check result
|
|
805
|
+
score = check_results[check_crit_names[i]]
|
|
806
|
+
else:
|
|
807
|
+
# No matching check result — assume neutral score
|
|
808
|
+
score = 0.5
|
|
809
|
+
weighted_sum += score * weight
|
|
810
|
+
total_weight += weight
|
|
811
|
+
|
|
812
|
+
# Normalize to [0.0, 1.0] if weights don't sum to 1.0
|
|
813
|
+
if total_weight > 0:
|
|
814
|
+
raw_score = weighted_sum / total_weight
|
|
815
|
+
else:
|
|
816
|
+
raw_score = 0.0
|
|
817
|
+
|
|
818
|
+
# Clamp to [0.0, 1.0]
|
|
819
|
+
return max(0.0, min(1.0, raw_score))
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
def _rank_strategies(scores):
|
|
823
|
+
"""Sort strategies by score descending and assign ranks.
|
|
824
|
+
|
|
825
|
+
Args:
|
|
826
|
+
scores: Dict of {strategy_id: score_float}.
|
|
827
|
+
|
|
828
|
+
Returns:
|
|
829
|
+
List of dicts: [{rank, strategy_id, score}, ...] ordered by score desc.
|
|
830
|
+
"""
|
|
831
|
+
sorted_items = sorted(scores.items(), key=lambda x: x[1], reverse=True)
|
|
832
|
+
ranked = []
|
|
833
|
+
for rank_idx, (strategy_id, score) in enumerate(sorted_items, start=1):
|
|
834
|
+
ranked.append({
|
|
835
|
+
"rank": rank_idx,
|
|
836
|
+
"strategy_id": strategy_id,
|
|
837
|
+
"score": round(score, 4),
|
|
838
|
+
})
|
|
839
|
+
return ranked
|
|
840
|
+
|
|
841
|
+
|
|
842
|
+
# ============================================================================
|
|
843
|
+
# ATO impact, cost, and timeline estimation
|
|
844
|
+
# ============================================================================
|
|
845
|
+
|
|
846
|
+
def _assess_ato_impact(profile, strategy):
|
|
847
|
+
"""Determine the ATO impact level for the recommended strategy.
|
|
848
|
+
|
|
849
|
+
ATO impact levels:
|
|
850
|
+
none — rehost, retain, retire (no system change boundary)
|
|
851
|
+
low — replatform (minor infra changes)
|
|
852
|
+
medium — refactor (version change may affect compliance docs)
|
|
853
|
+
high — rearchitect (new architecture requires new ATO boundary)
|
|
854
|
+
critical — repurchase (completely new system, full new ATO)
|
|
855
|
+
|
|
856
|
+
Args:
|
|
857
|
+
profile: The application profile dict (unused in base impl but
|
|
858
|
+
available for future refinement).
|
|
859
|
+
strategy: Strategy ID string.
|
|
860
|
+
|
|
861
|
+
Returns:
|
|
862
|
+
String: one of 'none', 'low', 'medium', 'high', 'critical'.
|
|
863
|
+
"""
|
|
864
|
+
impact_map = {
|
|
865
|
+
"rehost": "none",
|
|
866
|
+
"replatform": "low",
|
|
867
|
+
"refactor": "medium",
|
|
868
|
+
"rearchitect": "high",
|
|
869
|
+
"repurchase": "critical",
|
|
870
|
+
"retire": "none",
|
|
871
|
+
"retain": "none",
|
|
872
|
+
}
|
|
873
|
+
return impact_map.get(strategy, "medium")
|
|
874
|
+
|
|
875
|
+
|
|
876
|
+
def _estimate_cost(profile, strategy, catalog):
|
|
877
|
+
"""Estimate migration cost in person-hours.
|
|
878
|
+
|
|
879
|
+
Formula: (LOC / 20) * effort_multiplier * complexity_factor
|
|
880
|
+
|
|
881
|
+
The complexity factor adjusts for codebase health:
|
|
882
|
+
- maintainability > 60: factor 0.8 (healthy code, faster work)
|
|
883
|
+
- maintainability 30-60: factor 1.0 (normal)
|
|
884
|
+
- maintainability < 30: factor 1.5 (poor code, slower work)
|
|
885
|
+
|
|
886
|
+
An additional adjustment is made for high cyclomatic complexity:
|
|
887
|
+
- avg_complexity > 25: +20%
|
|
888
|
+
- avg_complexity > 40: +40%
|
|
889
|
+
|
|
890
|
+
Args:
|
|
891
|
+
profile: Application profile dict.
|
|
892
|
+
strategy: Strategy ID string.
|
|
893
|
+
catalog: Parsed catalog dict.
|
|
894
|
+
|
|
895
|
+
Returns:
|
|
896
|
+
Integer: estimated person-hours.
|
|
897
|
+
"""
|
|
898
|
+
loc = max(profile.get("loc_code", 0), profile.get("loc_total", 0), 1)
|
|
899
|
+
|
|
900
|
+
# Find effort_multiplier from catalog
|
|
901
|
+
effort_multiplier = 1.0
|
|
902
|
+
for s in catalog.get("strategies", []):
|
|
903
|
+
if s["id"] == strategy:
|
|
904
|
+
effort_multiplier = s.get("effort_multiplier", 1.0)
|
|
905
|
+
break
|
|
906
|
+
|
|
907
|
+
# Complexity factor based on maintainability index
|
|
908
|
+
maint = profile.get("maintainability_index", 50)
|
|
909
|
+
if maint > 60:
|
|
910
|
+
complexity_factor = 0.8
|
|
911
|
+
elif maint >= 30:
|
|
912
|
+
complexity_factor = 1.0
|
|
913
|
+
else:
|
|
914
|
+
complexity_factor = 1.5
|
|
915
|
+
|
|
916
|
+
# Cyclomatic complexity adjustment
|
|
917
|
+
avg_cx = profile.get("avg_complexity", 0)
|
|
918
|
+
cx_adjustment = 1.0
|
|
919
|
+
if avg_cx > 40:
|
|
920
|
+
cx_adjustment = 1.4
|
|
921
|
+
elif avg_cx > 25:
|
|
922
|
+
cx_adjustment = 1.2
|
|
923
|
+
|
|
924
|
+
base_hours = loc / 20.0
|
|
925
|
+
total_hours = base_hours * effort_multiplier * complexity_factor * cx_adjustment
|
|
926
|
+
|
|
927
|
+
# Minimum cost: 8 hours (1 day) for any migration activity
|
|
928
|
+
return max(8, int(math.ceil(total_hours)))
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
def _estimate_timeline(profile, strategy, catalog):
|
|
932
|
+
"""Estimate migration timeline in weeks.
|
|
933
|
+
|
|
934
|
+
Formula: cost_hours / 40 (1 FTE equivalent per week).
|
|
935
|
+
Minimum 2 weeks for any strategy.
|
|
936
|
+
|
|
937
|
+
Also considers the catalog's typical_timeline_weeks as a floor/ceiling
|
|
938
|
+
sanity check.
|
|
939
|
+
|
|
940
|
+
Args:
|
|
941
|
+
profile: Application profile dict.
|
|
942
|
+
strategy: Strategy ID string.
|
|
943
|
+
catalog: Parsed catalog dict.
|
|
944
|
+
|
|
945
|
+
Returns:
|
|
946
|
+
Integer: estimated weeks.
|
|
947
|
+
"""
|
|
948
|
+
cost_hours = _estimate_cost(profile, strategy, catalog)
|
|
949
|
+
raw_weeks = cost_hours / 40.0
|
|
950
|
+
|
|
951
|
+
# Look up catalog typical timeline for bounds checking
|
|
952
|
+
typical_min = 1
|
|
953
|
+
typical_max = 999
|
|
954
|
+
for s in catalog.get("strategies", []):
|
|
955
|
+
if s["id"] == strategy:
|
|
956
|
+
timeline = s.get("typical_timeline_weeks", {})
|
|
957
|
+
typical_min = timeline.get("min", 1)
|
|
958
|
+
typical_max = timeline.get("max", 999)
|
|
959
|
+
break
|
|
960
|
+
|
|
961
|
+
# Apply minimum of 2 weeks
|
|
962
|
+
weeks = max(2, int(math.ceil(raw_weeks)))
|
|
963
|
+
|
|
964
|
+
# Clamp to catalog bounds (with some flexibility — allow 50% over max)
|
|
965
|
+
weeks = max(weeks, typical_min)
|
|
966
|
+
weeks = min(weeks, int(typical_max * 1.5))
|
|
967
|
+
|
|
968
|
+
return weeks
|
|
969
|
+
|
|
970
|
+
|
|
971
|
+
# ============================================================================
|
|
972
|
+
# Tech debt reduction estimator
|
|
973
|
+
# ============================================================================
|
|
974
|
+
|
|
975
|
+
def _estimate_tech_debt_reduction(profile, strategy):
|
|
976
|
+
"""Estimate the percentage of technical debt addressed by the strategy.
|
|
977
|
+
|
|
978
|
+
Different strategies address different amounts of existing tech debt:
|
|
979
|
+
retain: 0% — no changes
|
|
980
|
+
rehost: 5% — minimal infra-related debt resolved
|
|
981
|
+
replatform: 15% — platform-level debt resolved
|
|
982
|
+
refactor: 50% — direct code-level debt remediation
|
|
983
|
+
rearchitect: 80% — near-complete rebuild eliminates most debt
|
|
984
|
+
repurchase: 90% — new system eliminates legacy debt
|
|
985
|
+
retire: 100% — system removed entirely
|
|
986
|
+
|
|
987
|
+
Args:
|
|
988
|
+
profile: Application profile dict.
|
|
989
|
+
strategy: Strategy ID string.
|
|
990
|
+
|
|
991
|
+
Returns:
|
|
992
|
+
Float: percentage of tech debt reduction (0.0 to 100.0).
|
|
993
|
+
"""
|
|
994
|
+
reduction_map = {
|
|
995
|
+
"retain": 0.0,
|
|
996
|
+
"rehost": 5.0,
|
|
997
|
+
"replatform": 15.0,
|
|
998
|
+
"refactor": 50.0,
|
|
999
|
+
"rearchitect": 80.0,
|
|
1000
|
+
"repurchase": 90.0,
|
|
1001
|
+
"retire": 100.0,
|
|
1002
|
+
}
|
|
1003
|
+
return reduction_map.get(strategy, 0.0)
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
# ============================================================================
|
|
1007
|
+
# Risk scoring
|
|
1008
|
+
# ============================================================================
|
|
1009
|
+
|
|
1010
|
+
def _compute_risk_score(profile, strategy, catalog):
|
|
1011
|
+
"""Compute a risk score in [0.0, 1.0] combining strategy risk, profile
|
|
1012
|
+
health, and ATO impact.
|
|
1013
|
+
|
|
1014
|
+
Components (weighted):
|
|
1015
|
+
- Strategy inherent risk (from catalog risk_level): 40%
|
|
1016
|
+
- Application health risk (inverse of maintainability): 30%
|
|
1017
|
+
- ATO impact risk: 20%
|
|
1018
|
+
- Dependency risk (count of external deps): 10%
|
|
1019
|
+
|
|
1020
|
+
Args:
|
|
1021
|
+
profile: Application profile dict.
|
|
1022
|
+
strategy: Strategy ID string.
|
|
1023
|
+
catalog: Parsed catalog dict.
|
|
1024
|
+
|
|
1025
|
+
Returns:
|
|
1026
|
+
Float risk score in [0.0, 1.0].
|
|
1027
|
+
"""
|
|
1028
|
+
# Strategy inherent risk
|
|
1029
|
+
strategy_risk = 0.5
|
|
1030
|
+
for s in catalog.get("strategies", []):
|
|
1031
|
+
if s["id"] == strategy:
|
|
1032
|
+
strategy_risk = RISK_LEVEL_MAP.get(s.get("risk_level", "medium"), 0.5)
|
|
1033
|
+
break
|
|
1034
|
+
|
|
1035
|
+
# Application health risk: inverse maintainability (0-100 scale)
|
|
1036
|
+
maint = profile.get("maintainability_index", 50)
|
|
1037
|
+
health_risk = max(0.0, min(1.0, 1.0 - (maint / 100.0)))
|
|
1038
|
+
|
|
1039
|
+
# ATO impact risk
|
|
1040
|
+
ato_impact = _assess_ato_impact(profile, strategy)
|
|
1041
|
+
ato_risk = ATO_IMPACT_ORDER.get(ato_impact, 2) / 4.0
|
|
1042
|
+
|
|
1043
|
+
# Dependency risk
|
|
1044
|
+
ext_deps = profile.get("external_dep_count", 0)
|
|
1045
|
+
if ext_deps < 5:
|
|
1046
|
+
dep_risk = 0.0
|
|
1047
|
+
elif ext_deps <= 15:
|
|
1048
|
+
dep_risk = 0.3
|
|
1049
|
+
elif ext_deps <= 30:
|
|
1050
|
+
dep_risk = 0.6
|
|
1051
|
+
else:
|
|
1052
|
+
dep_risk = 1.0
|
|
1053
|
+
|
|
1054
|
+
# Weighted combination
|
|
1055
|
+
risk = (
|
|
1056
|
+
strategy_risk * 0.4
|
|
1057
|
+
+ health_risk * 0.3
|
|
1058
|
+
+ ato_risk * 0.2
|
|
1059
|
+
+ dep_risk * 0.1
|
|
1060
|
+
)
|
|
1061
|
+
return round(max(0.0, min(1.0, risk)), 4)
|
|
1062
|
+
|
|
1063
|
+
|
|
1064
|
+
# ============================================================================
|
|
1065
|
+
# Main orchestrator
|
|
1066
|
+
# ============================================================================
|
|
1067
|
+
|
|
1068
|
+
def _get_ui_complexity(app_id, project_id, db_path=None):
|
|
1069
|
+
"""Query stored UI analysis for a legacy application.
|
|
1070
|
+
|
|
1071
|
+
If tools/modernization/ui_analyzer.py has been run against screenshots
|
|
1072
|
+
of this application, the complexity score is stored as JSON in the
|
|
1073
|
+
legacy_applications metadata column.
|
|
1074
|
+
|
|
1075
|
+
Args:
|
|
1076
|
+
app_id: Legacy application ID.
|
|
1077
|
+
project_id: Project ID.
|
|
1078
|
+
db_path: Optional database path override.
|
|
1079
|
+
|
|
1080
|
+
Returns:
|
|
1081
|
+
Float complexity score (0.0-1.0) or None if no UI analysis exists.
|
|
1082
|
+
"""
|
|
1083
|
+
try:
|
|
1084
|
+
conn = _get_db(db_path)
|
|
1085
|
+
row = conn.execute(
|
|
1086
|
+
"SELECT metadata FROM legacy_applications WHERE id = ?", (app_id,)
|
|
1087
|
+
).fetchone()
|
|
1088
|
+
conn.close()
|
|
1089
|
+
|
|
1090
|
+
if row and row["metadata"]:
|
|
1091
|
+
metadata = json.loads(row["metadata"]) if isinstance(row["metadata"], str) else row["metadata"]
|
|
1092
|
+
ui_analysis = metadata.get("ui_analysis", {})
|
|
1093
|
+
if "complexity_score" in ui_analysis:
|
|
1094
|
+
return float(ui_analysis["complexity_score"])
|
|
1095
|
+
except Exception:
|
|
1096
|
+
pass
|
|
1097
|
+
return None
|
|
1098
|
+
|
|
1099
|
+
|
|
1100
|
+
def _apply_ui_complexity_adjustment(strategy_scores, ui_complexity):
|
|
1101
|
+
"""Apply UI complexity adjustment to 7R strategy scores.
|
|
1102
|
+
|
|
1103
|
+
High UI complexity favors Rearchitect, penalizes Rehost.
|
|
1104
|
+
Low UI complexity favors Replatform.
|
|
1105
|
+
This is an optional dimension (D85 — backward compatible).
|
|
1106
|
+
|
|
1107
|
+
Args:
|
|
1108
|
+
strategy_scores: Dict of strategy_id -> score.
|
|
1109
|
+
ui_complexity: Float 0.0-1.0.
|
|
1110
|
+
|
|
1111
|
+
Returns:
|
|
1112
|
+
Adjusted strategy_scores dict.
|
|
1113
|
+
"""
|
|
1114
|
+
if ui_complexity is None:
|
|
1115
|
+
return strategy_scores
|
|
1116
|
+
|
|
1117
|
+
# Weight for UI complexity dimension (10% of total)
|
|
1118
|
+
weight = 0.10
|
|
1119
|
+
|
|
1120
|
+
adjustments = {}
|
|
1121
|
+
if ui_complexity > 0.7:
|
|
1122
|
+
# High UI complexity → favors Rearchitect, penalizes Rehost
|
|
1123
|
+
adjustments = {
|
|
1124
|
+
"rehost": -weight * 0.5,
|
|
1125
|
+
"replatform": -weight * 0.2,
|
|
1126
|
+
"rearchitect": weight * 0.5,
|
|
1127
|
+
"refactor": weight * 0.3,
|
|
1128
|
+
}
|
|
1129
|
+
elif ui_complexity < 0.3:
|
|
1130
|
+
# Low UI complexity → favors Replatform
|
|
1131
|
+
adjustments = {
|
|
1132
|
+
"rehost": weight * 0.2,
|
|
1133
|
+
"replatform": weight * 0.4,
|
|
1134
|
+
"rearchitect": -weight * 0.1,
|
|
1135
|
+
}
|
|
1136
|
+
else:
|
|
1137
|
+
# Moderate UI complexity → slight Refactor bias
|
|
1138
|
+
adjustments = {
|
|
1139
|
+
"refactor": weight * 0.2,
|
|
1140
|
+
"rearchitect": weight * 0.1,
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
adjusted = dict(strategy_scores)
|
|
1144
|
+
for strategy_id, adj in adjustments.items():
|
|
1145
|
+
if strategy_id in adjusted:
|
|
1146
|
+
adjusted[strategy_id] = max(0.0, min(1.0, adjusted[strategy_id] + adj))
|
|
1147
|
+
|
|
1148
|
+
return adjusted
|
|
1149
|
+
|
|
1150
|
+
|
|
1151
|
+
def run_seven_r_assessment(project_id, app_id, custom_weights=None, db_path=None):
|
|
1152
|
+
"""Orchestrate a full 7R assessment for one legacy application.
|
|
1153
|
+
|
|
1154
|
+
Steps:
|
|
1155
|
+
1. Load the 7Rs catalog
|
|
1156
|
+
2. Build the application profile from legacy_* tables
|
|
1157
|
+
3. Run all 7 fitness check functions
|
|
1158
|
+
4. Score each strategy against its catalog criteria
|
|
1159
|
+
4b. (Optional) Apply UI complexity adjustment if analysis available
|
|
1160
|
+
5. Rank strategies by score
|
|
1161
|
+
6. Assess ATO impact for recommended (top-ranked) strategy
|
|
1162
|
+
7. Estimate cost and timeline
|
|
1163
|
+
8. Store results in migration_assessments table (INSERT OR REPLACE)
|
|
1164
|
+
9. Return the complete assessment dict
|
|
1165
|
+
|
|
1166
|
+
Args:
|
|
1167
|
+
project_id: The project ID for context.
|
|
1168
|
+
app_id: The legacy application ID to assess.
|
|
1169
|
+
custom_weights: Optional dict of custom weights per strategy.
|
|
1170
|
+
db_path: Optional database path override.
|
|
1171
|
+
|
|
1172
|
+
Returns:
|
|
1173
|
+
Dict containing the full assessment: scores, ranking, recommendation,
|
|
1174
|
+
cost, timeline, ATO impact, evidence, and metadata.
|
|
1175
|
+
"""
|
|
1176
|
+
catalog = load_seven_rs_catalog()
|
|
1177
|
+
profile = _get_app_profile(app_id, db_path=db_path)
|
|
1178
|
+
|
|
1179
|
+
# Run all fitness checks
|
|
1180
|
+
fitness_results = {
|
|
1181
|
+
"rehost": _check_rehost_fitness(profile),
|
|
1182
|
+
"replatform": _check_replatform_fitness(profile),
|
|
1183
|
+
"refactor": _check_refactor_fitness(profile),
|
|
1184
|
+
"rearchitect": _check_rearchitect_fitness(profile),
|
|
1185
|
+
"repurchase": _check_repurchase_fitness(profile),
|
|
1186
|
+
"retire": _check_retire_fitness(profile),
|
|
1187
|
+
"retain": _check_retain_fitness(profile),
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
# Build a lookup: strategy_id → scoring_criteria from catalog
|
|
1191
|
+
catalog_criteria_map = {}
|
|
1192
|
+
for strat in catalog.get("strategies", []):
|
|
1193
|
+
catalog_criteria_map[strat["id"]] = strat.get("scoring_criteria", {})
|
|
1194
|
+
|
|
1195
|
+
# Score each strategy
|
|
1196
|
+
strategy_scores = {}
|
|
1197
|
+
for strategy_id, check_results in fitness_results.items():
|
|
1198
|
+
cat_criteria = catalog_criteria_map.get(strategy_id, {})
|
|
1199
|
+
strategy_scores[strategy_id] = _score_strategy(
|
|
1200
|
+
strategy_id, check_results, cat_criteria, weights=custom_weights
|
|
1201
|
+
)
|
|
1202
|
+
|
|
1203
|
+
# Optional: Apply UI complexity adjustment (D85 — backward compatible)
|
|
1204
|
+
ui_complexity = _get_ui_complexity(app_id, project_id, db_path=db_path)
|
|
1205
|
+
if ui_complexity is not None:
|
|
1206
|
+
strategy_scores = _apply_ui_complexity_adjustment(strategy_scores, ui_complexity)
|
|
1207
|
+
|
|
1208
|
+
# Rank strategies
|
|
1209
|
+
ranking = _rank_strategies(strategy_scores)
|
|
1210
|
+
recommended = ranking[0]["strategy_id"] if ranking else "retain"
|
|
1211
|
+
|
|
1212
|
+
# ATO impact for recommended strategy
|
|
1213
|
+
ato_impact = _assess_ato_impact(profile, recommended)
|
|
1214
|
+
|
|
1215
|
+
# Cost and timeline for recommended strategy
|
|
1216
|
+
cost_hours = _estimate_cost(profile, recommended, catalog)
|
|
1217
|
+
timeline_weeks = _estimate_timeline(profile, recommended, catalog)
|
|
1218
|
+
|
|
1219
|
+
# Risk score for recommended strategy
|
|
1220
|
+
risk_score = _compute_risk_score(profile, recommended, catalog)
|
|
1221
|
+
|
|
1222
|
+
# Tech debt reduction for recommended strategy
|
|
1223
|
+
tech_debt_reduction = _estimate_tech_debt_reduction(profile, recommended)
|
|
1224
|
+
|
|
1225
|
+
# Compile the scoring weights used
|
|
1226
|
+
scoring_weights = {}
|
|
1227
|
+
for strat in catalog.get("strategies", []):
|
|
1228
|
+
weights_for_strat = {}
|
|
1229
|
+
for crit_name, crit_info in strat.get("scoring_criteria", {}).items():
|
|
1230
|
+
weights_for_strat[crit_name] = crit_info.get("weight", 0.0)
|
|
1231
|
+
scoring_weights[strat["id"]] = weights_for_strat
|
|
1232
|
+
|
|
1233
|
+
if custom_weights:
|
|
1234
|
+
for strat_id, overrides in custom_weights.items():
|
|
1235
|
+
if strat_id in scoring_weights:
|
|
1236
|
+
scoring_weights[strat_id].update(overrides)
|
|
1237
|
+
|
|
1238
|
+
# Compile evidence
|
|
1239
|
+
evidence = {
|
|
1240
|
+
"fitness_results": {k: {ck: round(cv, 4) for ck, cv in v.items()} for k, v in fitness_results.items()},
|
|
1241
|
+
"strategy_scores": {k: round(v, 4) for k, v in strategy_scores.items()},
|
|
1242
|
+
"ranking": ranking,
|
|
1243
|
+
"profile_summary": {
|
|
1244
|
+
"name": profile.get("name", "unknown"),
|
|
1245
|
+
"primary_language": profile.get("primary_language"),
|
|
1246
|
+
"language_version": profile.get("language_version"),
|
|
1247
|
+
"framework": profile.get("framework"),
|
|
1248
|
+
"framework_version": profile.get("framework_version"),
|
|
1249
|
+
"loc_total": profile.get("loc_total"),
|
|
1250
|
+
"loc_code": profile.get("loc_code"),
|
|
1251
|
+
"file_count": profile.get("file_count"),
|
|
1252
|
+
"component_count": profile.get("component_count"),
|
|
1253
|
+
"dependency_count": profile.get("dependency_count"),
|
|
1254
|
+
"api_count": profile.get("api_count"),
|
|
1255
|
+
"db_schema_count": profile.get("db_schema_count"),
|
|
1256
|
+
"complexity_score": profile.get("complexity_score"),
|
|
1257
|
+
"maintainability_index": profile.get("maintainability_index"),
|
|
1258
|
+
"tech_debt_hours": profile.get("tech_debt_hours"),
|
|
1259
|
+
"avg_complexity": round(profile.get("avg_complexity", 0), 2),
|
|
1260
|
+
"avg_coupling": round(profile.get("avg_coupling", 0), 2),
|
|
1261
|
+
"ui_complexity": round(ui_complexity, 2) if ui_complexity is not None else None,
|
|
1262
|
+
},
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
# Build the assessment record
|
|
1266
|
+
assessment_id = str(uuid.uuid4())
|
|
1267
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
1268
|
+
|
|
1269
|
+
assessment = {
|
|
1270
|
+
"id": assessment_id,
|
|
1271
|
+
"legacy_app_id": app_id,
|
|
1272
|
+
"component_id": None, # app-level assessment
|
|
1273
|
+
"assessment_scope": "application",
|
|
1274
|
+
"rehost_score": round(strategy_scores.get("rehost", 0.0), 4),
|
|
1275
|
+
"replatform_score": round(strategy_scores.get("replatform", 0.0), 4),
|
|
1276
|
+
"refactor_score": round(strategy_scores.get("refactor", 0.0), 4),
|
|
1277
|
+
"rearchitect_score": round(strategy_scores.get("rearchitect", 0.0), 4),
|
|
1278
|
+
"repurchase_score": round(strategy_scores.get("repurchase", 0.0), 4),
|
|
1279
|
+
"retire_score": round(strategy_scores.get("retire", 0.0), 4),
|
|
1280
|
+
"retain_score": round(strategy_scores.get("retain", 0.0), 4),
|
|
1281
|
+
"recommended_strategy": recommended,
|
|
1282
|
+
"cost_estimate_hours": cost_hours,
|
|
1283
|
+
"risk_score": risk_score,
|
|
1284
|
+
"timeline_weeks": timeline_weeks,
|
|
1285
|
+
"ato_impact": ato_impact,
|
|
1286
|
+
"tech_debt_reduction": tech_debt_reduction,
|
|
1287
|
+
"scoring_weights": json.dumps(scoring_weights),
|
|
1288
|
+
"evidence": json.dumps(evidence),
|
|
1289
|
+
"assessed_at": now,
|
|
1290
|
+
"project_id": project_id,
|
|
1291
|
+
"ranking": ranking,
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
# Persist to database
|
|
1295
|
+
_persist_assessment(assessment, db_path=db_path)
|
|
1296
|
+
|
|
1297
|
+
return assessment
|
|
1298
|
+
|
|
1299
|
+
|
|
1300
|
+
def _persist_assessment(assessment, db_path=None):
|
|
1301
|
+
"""Write the assessment record to migration_assessments via INSERT OR REPLACE.
|
|
1302
|
+
|
|
1303
|
+
Args:
|
|
1304
|
+
assessment: Dict with all assessment fields.
|
|
1305
|
+
db_path: Optional database path override.
|
|
1306
|
+
"""
|
|
1307
|
+
conn = _get_db(db_path)
|
|
1308
|
+
try:
|
|
1309
|
+
conn.execute(
|
|
1310
|
+
"""INSERT OR REPLACE INTO migration_assessments
|
|
1311
|
+
(id, legacy_app_id, component_id, assessment_scope,
|
|
1312
|
+
rehost_score, replatform_score, refactor_score,
|
|
1313
|
+
rearchitect_score, repurchase_score, retire_score,
|
|
1314
|
+
retain_score, recommended_strategy, cost_estimate_hours,
|
|
1315
|
+
risk_score, timeline_weeks, ato_impact, tech_debt_reduction,
|
|
1316
|
+
scoring_weights, evidence, assessed_at)
|
|
1317
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
|
1318
|
+
(
|
|
1319
|
+
assessment["id"],
|
|
1320
|
+
assessment["legacy_app_id"],
|
|
1321
|
+
assessment.get("component_id"),
|
|
1322
|
+
assessment["assessment_scope"],
|
|
1323
|
+
assessment["rehost_score"],
|
|
1324
|
+
assessment["replatform_score"],
|
|
1325
|
+
assessment["refactor_score"],
|
|
1326
|
+
assessment["rearchitect_score"],
|
|
1327
|
+
assessment["repurchase_score"],
|
|
1328
|
+
assessment["retire_score"],
|
|
1329
|
+
assessment["retain_score"],
|
|
1330
|
+
assessment["recommended_strategy"],
|
|
1331
|
+
assessment["cost_estimate_hours"],
|
|
1332
|
+
assessment["risk_score"],
|
|
1333
|
+
assessment["timeline_weeks"],
|
|
1334
|
+
assessment["ato_impact"],
|
|
1335
|
+
assessment["tech_debt_reduction"],
|
|
1336
|
+
assessment["scoring_weights"],
|
|
1337
|
+
assessment["evidence"],
|
|
1338
|
+
assessment["assessed_at"],
|
|
1339
|
+
),
|
|
1340
|
+
)
|
|
1341
|
+
conn.commit()
|
|
1342
|
+
finally:
|
|
1343
|
+
conn.close()
|
|
1344
|
+
|
|
1345
|
+
|
|
1346
|
+
# ============================================================================
|
|
1347
|
+
# Decision matrix display
|
|
1348
|
+
# ============================================================================
|
|
1349
|
+
|
|
1350
|
+
def generate_decision_matrix(app_id, db_path=None):
|
|
1351
|
+
"""Pretty-print a decision matrix with all 7 strategies scored.
|
|
1352
|
+
|
|
1353
|
+
Reads the most recent assessment for the given app from the database.
|
|
1354
|
+
If no assessment exists, returns a message indicating so.
|
|
1355
|
+
|
|
1356
|
+
The matrix includes:
|
|
1357
|
+
- Strategy name
|
|
1358
|
+
- Score (0.0-1.0)
|
|
1359
|
+
- Rank
|
|
1360
|
+
- Risk level
|
|
1361
|
+
- Estimated cost (hours)
|
|
1362
|
+
- Timeline (weeks)
|
|
1363
|
+
- ATO impact
|
|
1364
|
+
- Tech debt reduction
|
|
1365
|
+
|
|
1366
|
+
Ends with the recommended strategy and rationale.
|
|
1367
|
+
|
|
1368
|
+
Args:
|
|
1369
|
+
app_id: The legacy application ID.
|
|
1370
|
+
db_path: Optional database path override.
|
|
1371
|
+
|
|
1372
|
+
Returns:
|
|
1373
|
+
String containing the formatted decision matrix.
|
|
1374
|
+
"""
|
|
1375
|
+
conn = _get_db(db_path)
|
|
1376
|
+
try:
|
|
1377
|
+
row = conn.execute(
|
|
1378
|
+
"""SELECT * FROM migration_assessments
|
|
1379
|
+
WHERE legacy_app_id = ?
|
|
1380
|
+
ORDER BY assessed_at DESC LIMIT 1""",
|
|
1381
|
+
(app_id,),
|
|
1382
|
+
).fetchone()
|
|
1383
|
+
finally:
|
|
1384
|
+
conn.close()
|
|
1385
|
+
|
|
1386
|
+
if row is None:
|
|
1387
|
+
return (
|
|
1388
|
+
f"No assessment found for application '{app_id}'.\n"
|
|
1389
|
+
"Run an assessment first with: --project-id <PID> --app-id <AID>"
|
|
1390
|
+
)
|
|
1391
|
+
|
|
1392
|
+
row_dict = dict(row)
|
|
1393
|
+
evidence = json.loads(row_dict.get("evidence", "{}"))
|
|
1394
|
+
ranking = evidence.get("ranking", [])
|
|
1395
|
+
profile_summary = evidence.get("profile_summary", {})
|
|
1396
|
+
fitness_results = evidence.get("fitness_results", {})
|
|
1397
|
+
strategy_scores = evidence.get("strategy_scores", {})
|
|
1398
|
+
|
|
1399
|
+
catalog = load_seven_rs_catalog()
|
|
1400
|
+
|
|
1401
|
+
# Build per-strategy detail rows
|
|
1402
|
+
strategy_details = []
|
|
1403
|
+
for entry in ranking:
|
|
1404
|
+
sid = entry["strategy_id"]
|
|
1405
|
+
score = entry["score"]
|
|
1406
|
+
rank = entry["rank"]
|
|
1407
|
+
|
|
1408
|
+
# Look up catalog info
|
|
1409
|
+
cat_info = {}
|
|
1410
|
+
for s in catalog.get("strategies", []):
|
|
1411
|
+
if s["id"] == sid:
|
|
1412
|
+
cat_info = s
|
|
1413
|
+
break
|
|
1414
|
+
|
|
1415
|
+
risk_level = cat_info.get("risk_level", "medium")
|
|
1416
|
+
ato = _assess_ato_impact(profile_summary, sid)
|
|
1417
|
+
cost_h = _estimate_cost(profile_summary if "loc_code" in profile_summary else {"loc_code": profile_summary.get("loc_code", 0), "loc_total": profile_summary.get("loc_total", 0), "maintainability_index": profile_summary.get("maintainability_index", 50), "avg_complexity": profile_summary.get("avg_complexity", 0)}, sid, catalog)
|
|
1418
|
+
timeline_w = _estimate_timeline({"loc_code": profile_summary.get("loc_code", 0), "loc_total": profile_summary.get("loc_total", 0), "maintainability_index": profile_summary.get("maintainability_index", 50), "avg_complexity": profile_summary.get("avg_complexity", 0)}, sid, catalog)
|
|
1419
|
+
tdr = _estimate_tech_debt_reduction(profile_summary, sid)
|
|
1420
|
+
risk_s = _compute_risk_score({"maintainability_index": profile_summary.get("maintainability_index", 50), "external_dep_count": profile_summary.get("dependency_count", 0)}, sid, catalog)
|
|
1421
|
+
|
|
1422
|
+
strategy_details.append({
|
|
1423
|
+
"rank": rank,
|
|
1424
|
+
"name": cat_info.get("name", sid.title()),
|
|
1425
|
+
"id": sid,
|
|
1426
|
+
"score": score,
|
|
1427
|
+
"risk_level": risk_level,
|
|
1428
|
+
"risk_score": risk_s,
|
|
1429
|
+
"cost_hours": cost_h,
|
|
1430
|
+
"timeline_weeks": timeline_w,
|
|
1431
|
+
"ato_impact": ato,
|
|
1432
|
+
"tech_debt_reduction": tdr,
|
|
1433
|
+
})
|
|
1434
|
+
|
|
1435
|
+
# Format the matrix
|
|
1436
|
+
lines = []
|
|
1437
|
+
lines.append("=" * 100)
|
|
1438
|
+
lines.append("CUI // SP-CTI")
|
|
1439
|
+
lines.append("=" * 100)
|
|
1440
|
+
lines.append("")
|
|
1441
|
+
lines.append("7R MIGRATION STRATEGY DECISION MATRIX")
|
|
1442
|
+
lines.append(f"Application: {profile_summary.get('name', app_id)}")
|
|
1443
|
+
lines.append(f"Language: {profile_summary.get('primary_language', 'N/A')} {profile_summary.get('language_version', '')}")
|
|
1444
|
+
lines.append(f"Framework: {profile_summary.get('framework', 'N/A')} {profile_summary.get('framework_version', '')}")
|
|
1445
|
+
lines.append(f"LOC: {profile_summary.get('loc_total', 'N/A'):,}" if isinstance(profile_summary.get('loc_total'), (int, float)) else f"LOC: {profile_summary.get('loc_total', 'N/A')}")
|
|
1446
|
+
lines.append(f"Components: {profile_summary.get('component_count', 'N/A')}")
|
|
1447
|
+
lines.append(f"Assessed: {row_dict.get('assessed_at', 'N/A')}")
|
|
1448
|
+
lines.append("")
|
|
1449
|
+
lines.append("-" * 100)
|
|
1450
|
+
|
|
1451
|
+
# Table header
|
|
1452
|
+
header = f"{'Rank':<6}{'Strategy':<15}{'Score':<9}{'Risk':<10}{'Cost (hrs)':<12}{'Timeline':<12}{'ATO Impact':<14}{'Debt Reduction':<15}"
|
|
1453
|
+
lines.append(header)
|
|
1454
|
+
lines.append("-" * 100)
|
|
1455
|
+
|
|
1456
|
+
# Table rows
|
|
1457
|
+
for sd in strategy_details:
|
|
1458
|
+
marker = " <<" if sd["rank"] == 1 else ""
|
|
1459
|
+
row_str = (
|
|
1460
|
+
f"{sd['rank']:<6}"
|
|
1461
|
+
f"{sd['name']:<15}"
|
|
1462
|
+
f"{sd['score']:<9.4f}"
|
|
1463
|
+
f"{sd['risk_level']:<10}"
|
|
1464
|
+
f"{sd['cost_hours']:<12,}"
|
|
1465
|
+
f"{sd['timeline_weeks']:<10} wk "
|
|
1466
|
+
f"{sd['ato_impact']:<14}"
|
|
1467
|
+
f"{sd['tech_debt_reduction']:<10.0f}%"
|
|
1468
|
+
f"{marker}"
|
|
1469
|
+
)
|
|
1470
|
+
lines.append(row_str)
|
|
1471
|
+
|
|
1472
|
+
lines.append("-" * 100)
|
|
1473
|
+
lines.append("")
|
|
1474
|
+
|
|
1475
|
+
# Recommendation section
|
|
1476
|
+
recommended = row_dict.get("recommended_strategy", "unknown")
|
|
1477
|
+
rec_details = None
|
|
1478
|
+
for sd in strategy_details:
|
|
1479
|
+
if sd["id"] == recommended:
|
|
1480
|
+
rec_details = sd
|
|
1481
|
+
break
|
|
1482
|
+
|
|
1483
|
+
lines.append("RECOMMENDATION")
|
|
1484
|
+
lines.append(f" Strategy: {rec_details['name'] if rec_details else recommended.title()}")
|
|
1485
|
+
lines.append(f" Score: {rec_details['score']:.4f}" if rec_details else " Score: N/A")
|
|
1486
|
+
lines.append(f" Risk: {rec_details['risk_level'] if rec_details else 'N/A'} ({rec_details['risk_score']:.2f})" if rec_details else "")
|
|
1487
|
+
lines.append(f" Estimated Cost: {rec_details['cost_hours']:,} hours" if rec_details else " Estimated Cost: N/A")
|
|
1488
|
+
lines.append(f" Timeline: {rec_details['timeline_weeks']} weeks" if rec_details else " Timeline: N/A")
|
|
1489
|
+
lines.append(f" ATO Impact: {rec_details['ato_impact']}" if rec_details else " ATO Impact: N/A")
|
|
1490
|
+
lines.append(f" Debt Reduction: {rec_details['tech_debt_reduction']:.0f}%" if rec_details else " Debt Reduction: N/A")
|
|
1491
|
+
lines.append("")
|
|
1492
|
+
|
|
1493
|
+
# Rationale
|
|
1494
|
+
lines.append("RATIONALE")
|
|
1495
|
+
if rec_details:
|
|
1496
|
+
# Build a short rationale from the fitness scores
|
|
1497
|
+
fit = fitness_results.get(recommended, {})
|
|
1498
|
+
high_fit = [k for k, v in fit.items() if v >= 0.8]
|
|
1499
|
+
low_fit = [k for k, v in fit.items() if v <= 0.2]
|
|
1500
|
+
|
|
1501
|
+
if high_fit:
|
|
1502
|
+
lines.append(f" Strengths: {', '.join(high_fit)}")
|
|
1503
|
+
if low_fit:
|
|
1504
|
+
lines.append(f" Weaknesses: {', '.join(low_fit)}")
|
|
1505
|
+
|
|
1506
|
+
# Compare top two
|
|
1507
|
+
if len(strategy_details) >= 2:
|
|
1508
|
+
second = strategy_details[1]
|
|
1509
|
+
delta = rec_details["score"] - second["score"]
|
|
1510
|
+
lines.append(
|
|
1511
|
+
f" Margin: {recommended} leads {second['id']} by "
|
|
1512
|
+
f"{delta:.4f} ({delta * 100:.1f}%)"
|
|
1513
|
+
)
|
|
1514
|
+
if delta < 0.05:
|
|
1515
|
+
lines.append(
|
|
1516
|
+
" NOTE: Scores are very close. Manual review of "
|
|
1517
|
+
"business context and team capacity is recommended."
|
|
1518
|
+
)
|
|
1519
|
+
else:
|
|
1520
|
+
lines.append(" No detailed rationale available.")
|
|
1521
|
+
|
|
1522
|
+
lines.append("")
|
|
1523
|
+
|
|
1524
|
+
# Fitness detail section
|
|
1525
|
+
lines.append("FITNESS BREAKDOWN")
|
|
1526
|
+
lines.append("-" * 100)
|
|
1527
|
+
for sid in ["rehost", "replatform", "refactor", "rearchitect", "repurchase", "retire", "retain"]:
|
|
1528
|
+
fit = fitness_results.get(sid, {})
|
|
1529
|
+
if not fit:
|
|
1530
|
+
continue
|
|
1531
|
+
score = strategy_scores.get(sid, 0.0)
|
|
1532
|
+
criteria_strs = [f"{k}={v:.1f}" for k, v in fit.items()]
|
|
1533
|
+
lines.append(f" {sid:<14} (score: {score:.4f}): {', '.join(criteria_strs)}")
|
|
1534
|
+
lines.append("-" * 100)
|
|
1535
|
+
|
|
1536
|
+
lines.append("")
|
|
1537
|
+
lines.append("CUI // SP-CTI")
|
|
1538
|
+
lines.append("=" * 100)
|
|
1539
|
+
|
|
1540
|
+
return "\n".join(lines)
|
|
1541
|
+
|
|
1542
|
+
|
|
1543
|
+
# ============================================================================
|
|
1544
|
+
# CLI entry point
|
|
1545
|
+
# ============================================================================
|
|
1546
|
+
|
|
1547
|
+
def main():
|
|
1548
|
+
"""CLI entry point for the 7R assessment engine.
|
|
1549
|
+
|
|
1550
|
+
Arguments:
|
|
1551
|
+
--project-id (required): Project identifier
|
|
1552
|
+
--app-id (required): Legacy application identifier
|
|
1553
|
+
--weights (optional): Path to custom weights JSON file
|
|
1554
|
+
--json (flag): Output raw assessment as JSON
|
|
1555
|
+
--matrix (flag): Print the decision matrix table
|
|
1556
|
+
"""
|
|
1557
|
+
parser = argparse.ArgumentParser(
|
|
1558
|
+
description=(
|
|
1559
|
+
"7R Migration Strategy Recommendation Engine — "
|
|
1560
|
+
"Evaluates legacy applications against 7 cloud migration strategies "
|
|
1561
|
+
"and recommends the optimal path for DoD/GovCloud environments."
|
|
1562
|
+
),
|
|
1563
|
+
epilog="CUI // SP-CTI",
|
|
1564
|
+
)
|
|
1565
|
+
parser.add_argument(
|
|
1566
|
+
"--project-id",
|
|
1567
|
+
required=True,
|
|
1568
|
+
help="Project identifier (e.g., P-001)",
|
|
1569
|
+
)
|
|
1570
|
+
parser.add_argument(
|
|
1571
|
+
"--app-id",
|
|
1572
|
+
required=True,
|
|
1573
|
+
help="Legacy application identifier (e.g., A-001)",
|
|
1574
|
+
)
|
|
1575
|
+
parser.add_argument(
|
|
1576
|
+
"--weights",
|
|
1577
|
+
default=None,
|
|
1578
|
+
help="Path to custom weights JSON file (overrides catalog defaults)",
|
|
1579
|
+
)
|
|
1580
|
+
parser.add_argument(
|
|
1581
|
+
"--json",
|
|
1582
|
+
action="store_true",
|
|
1583
|
+
dest="output_json",
|
|
1584
|
+
help="Output the assessment as JSON",
|
|
1585
|
+
)
|
|
1586
|
+
parser.add_argument(
|
|
1587
|
+
"--matrix",
|
|
1588
|
+
action="store_true",
|
|
1589
|
+
help="Print the decision matrix table",
|
|
1590
|
+
)
|
|
1591
|
+
|
|
1592
|
+
args = parser.parse_args()
|
|
1593
|
+
|
|
1594
|
+
# Load custom weights if provided
|
|
1595
|
+
custom_weights = None
|
|
1596
|
+
if args.weights:
|
|
1597
|
+
weights_path = Path(args.weights)
|
|
1598
|
+
if not weights_path.exists():
|
|
1599
|
+
print(f"ERROR: Weights file not found: {weights_path}", file=sys.stderr)
|
|
1600
|
+
sys.exit(1)
|
|
1601
|
+
with open(weights_path, "r", encoding="utf-8") as fh:
|
|
1602
|
+
custom_weights = json.load(fh)
|
|
1603
|
+
|
|
1604
|
+
# Run the assessment
|
|
1605
|
+
try:
|
|
1606
|
+
assessment = run_seven_r_assessment(
|
|
1607
|
+
project_id=args.project_id,
|
|
1608
|
+
app_id=args.app_id,
|
|
1609
|
+
custom_weights=custom_weights,
|
|
1610
|
+
)
|
|
1611
|
+
except FileNotFoundError as exc:
|
|
1612
|
+
print(f"ERROR: {exc}", file=sys.stderr)
|
|
1613
|
+
sys.exit(1)
|
|
1614
|
+
except ValueError as exc:
|
|
1615
|
+
print(f"ERROR: {exc}", file=sys.stderr)
|
|
1616
|
+
sys.exit(1)
|
|
1617
|
+
|
|
1618
|
+
# Output
|
|
1619
|
+
if args.output_json:
|
|
1620
|
+
# Serialise — strip non-serializable fields
|
|
1621
|
+
output = dict(assessment)
|
|
1622
|
+
# ranking is already a list of dicts, safe to serialize
|
|
1623
|
+
output["scoring_weights"] = json.loads(output["scoring_weights"]) if isinstance(output["scoring_weights"], str) else output["scoring_weights"]
|
|
1624
|
+
output["evidence"] = json.loads(output["evidence"]) if isinstance(output["evidence"], str) else output["evidence"]
|
|
1625
|
+
print(json.dumps(output, indent=2, default=str))
|
|
1626
|
+
elif args.matrix:
|
|
1627
|
+
matrix_output = generate_decision_matrix(args.app_id)
|
|
1628
|
+
print(matrix_output)
|
|
1629
|
+
else:
|
|
1630
|
+
# Default: summary output
|
|
1631
|
+
print("=" * 60)
|
|
1632
|
+
print("CUI // SP-CTI")
|
|
1633
|
+
print("=" * 60)
|
|
1634
|
+
print(f"7R Assessment Complete — {assessment['legacy_app_id']}")
|
|
1635
|
+
print(f" Assessment ID: {assessment['id']}")
|
|
1636
|
+
print(f" Recommended Strategy: {assessment['recommended_strategy'].upper()}")
|
|
1637
|
+
print(f" Score: {assessment.get(assessment['recommended_strategy'] + '_score', 'N/A')}")
|
|
1638
|
+
print(f" Risk Score: {assessment['risk_score']}")
|
|
1639
|
+
print(f" Cost Estimate: {assessment['cost_estimate_hours']:,} hours")
|
|
1640
|
+
print(f" Timeline: {assessment['timeline_weeks']} weeks")
|
|
1641
|
+
print(f" ATO Impact: {assessment['ato_impact']}")
|
|
1642
|
+
print(f" Tech Debt Reduction: {assessment['tech_debt_reduction']:.0f}%")
|
|
1643
|
+
print()
|
|
1644
|
+
print("Strategy Rankings:")
|
|
1645
|
+
for entry in assessment["ranking"]:
|
|
1646
|
+
marker = " << RECOMMENDED" if entry["rank"] == 1 else ""
|
|
1647
|
+
print(f" #{entry['rank']} {entry['strategy_id']:<14} {entry['score']:.4f}{marker}")
|
|
1648
|
+
print()
|
|
1649
|
+
print("Run with --matrix for full decision matrix.")
|
|
1650
|
+
print("Run with --json for machine-readable output.")
|
|
1651
|
+
print("=" * 60)
|
|
1652
|
+
print("CUI // SP-CTI")
|
|
1653
|
+
print("=" * 60)
|
|
1654
|
+
|
|
1655
|
+
|
|
1656
|
+
if __name__ == "__main__":
|
|
1657
|
+
main()
|
|
1658
|
+
# [TEMPLATE: CUI // SP-CTI]
|