codd-dev 2.11.0__tar.gz → 2.13.0__tar.gz
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.
- {codd_dev-2.11.0 → codd_dev-2.13.0}/PKG-INFO +6 -3
- {codd_dev-2.11.0 → codd_dev-2.13.0}/README.md +5 -2
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/cli.py +20 -2
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/coverage_metrics.py +11 -1
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/checks/__init__.py +41 -1
- codd_dev-2.13.0/codd/dag/checks/ci_health.py +418 -0
- codd_dev-2.13.0/codd/dag/checks/opt_out.py +265 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/checks/user_journey_coherence.py +113 -1
- codd_dev-2.13.0/codd/dag/runner.py +146 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployer.py +97 -1
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/elicit/__init__.py +3 -1
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/elicit/engine.py +230 -3
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/elicit/finding.py +22 -3
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/templates/codd.yaml.tmpl +10 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/validator.py +30 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/stack_map.yaml +8 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/pyproject.toml +1 -1
- codd_dev-2.11.0/codd/dag/runner.py +0 -78
- {codd_dev-2.11.0 → codd_dev-2.13.0}/.gitignore +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/LICENSE +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/__main__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/_git_helper.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/ask_user_question_adapter.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/assembler.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/bridge.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/brownfield/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/brownfield/pipeline.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/clustering.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/coherence_adapters.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/coherence_engine.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/config.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/contracts.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/coverage_auditor.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/builder.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/checks/depends_on_consistency.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/checks/deployment_completeness.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/checks/edge_validity.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/checks/environment_coverage.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/checks/implementation_coverage.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/checks/node_completeness.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/checks/task_completion.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/checks/transitive_closure.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/coverage_axes.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/defaults/cli.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/defaults/cpp_embedded.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/defaults/csharp.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/defaults/elixir.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/defaults/generic.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/defaults/iot.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/defaults/java.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/defaults/kotlin.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/defaults/mobile.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/defaults/ruby.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/defaults/rust.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/defaults/scala.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/defaults/swift.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/defaults/test_frameworks.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/defaults/web.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/dag/extractor.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/defaults.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deploy_targets/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deploy_targets/app_service.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deploy_targets/base.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deploy_targets/docker_compose.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/checks/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/defaults/deploy_targets.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/defaults/runtime_capability_inference.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/defaults/schema_providers.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/defaults/verification_templates.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/extractor.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/ai_command.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/llm_consideration.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/schema/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/schema/prisma.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/target/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/target/docker_compose.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/verification/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/verification/assertion_handlers.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/verification/cdp_browser.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/verification/cdp_engines.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/verification/cdp_launchers.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/verification/cdp_wire.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/verification/curl.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/verification/form_strategies.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/verification/means_catalog.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/deployment/providers/verification/playwright.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/design_md.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/diff/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/diff/apply.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/diff/engine.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/diff/persistence.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/diff/templates/diff_prompt.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/drift.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/e2e_extractor.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/e2e_generator.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/e2e_runner.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/elicit/apply.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/elicit/formatters/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/elicit/formatters/base.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/elicit/formatters/interactive.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/elicit/formatters/json_fmt.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/elicit/formatters/md.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/elicit/lexicon_loader.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/elicit/persistence.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/elicit/templates/elicit_prompt_L0.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/env_refs.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/extract_ai.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/extractor.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/fixer.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/fixup_drift.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/fixup_drift_strategies/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/fixup_drift_strategies/design_token_drift.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/fixup_drift_strategies/lexicon_violation.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/fixup_drift_strategies/url_drift.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/generator.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/graph.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/hitl_session.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/hooks/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/hooks/pre-commit +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/hooks/recipes/claude_settings_example.json +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/hooks/recipes/codex_hook.sh +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/hooks/recipes/git_post_commit.sh +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/hooks/recipes/git_pre_commit.sh +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/implementer/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/implementer/chunked_runner.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/implementer/typecheck_loop.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/implementer.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/inheritance.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/init/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/init/lexicon_suggest.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/init/llm_lexicon_suggester.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/init/stack_detector.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/knowledge_fetcher.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/lexicon.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/lexicon_cli/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/lexicon_cli/formatters/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/lexicon_cli/formatters/html.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/lexicon_cli/formatters/json_fmt.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/lexicon_cli/formatters/md.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/lexicon_cli/inspector.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/lexicon_cli/manager.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/lexicon_cli/reporter.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/lexicon_cli/threshold.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/approval.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/best_practice_augmenter.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/criteria_expander.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/design_doc_extractor.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/impl_step_deriver.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/means_catalog_loader.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/parser.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/plan_deriver.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/prompt_builder.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/strategy_validator.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/templates/best_practice_augment_meta.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/templates/criteria_expand_meta.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/templates/design_doc_extract_meta.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/templates/impl_step_derive_meta.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/templates/implementation_step_catalog.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/templates/meta_instruction.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/templates/plan_derive_meta.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/llm/templates/verification_means_catalog.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/mcp_server.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/measure.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/parsing.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/planner.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/policy.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/preflight/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/preflight/defaults/cli.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/preflight/defaults/iot.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/preflight/defaults/mobile.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/preflight/defaults/web.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/propagate.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/propagator.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/registry.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/approval_repair.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/engine.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/git_patcher.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/history.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/llm_repair_engine.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/loop.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/primary_picker.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/proof_breaks.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/repair_result.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/repairability_classifier.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/schema.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/templates/analyze_meta.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/templates/propose_meta.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/templates/repair_strategy_meta.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/templates/repairability_meta.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair/verify_runner.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/repair_slice.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/require.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/require_plugins.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/require_propagate.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/required_artifacts/defaults/cli.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/required_artifacts/defaults/iot.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/required_artifacts/defaults/mobile.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/required_artifacts/defaults/web.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/required_artifacts_deriver.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/requirement_completeness/defaults/cli.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/requirement_completeness/defaults/iot.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/requirement_completeness/defaults/mobile.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/requirement_completeness/defaults/web.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/requirement_completeness_auditor.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/restore.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/routes_extractor.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/scanner.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/schema_refs.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/screen_flow_validator.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/screen_transition_extractor.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/screen_transitions/defaults.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/synth.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/templates/conventions.yaml.tmpl +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/templates/data_dependencies.yaml.tmpl +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/templates/doc_links.yaml.tmpl +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/templates/extract_ai_prompt_baseline.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/templates/extracted/api-contract.md.j2 +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/templates/extracted/architecture-overview.md.j2 +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/templates/extracted/module-detail.md.j2 +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/templates/extracted/schema-design.md.j2 +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/templates/extracted/system-context.md.j2 +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/templates/gitignore.tmpl +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/templates/lexicon_questions.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/templates/lexicon_schema.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/templates/overrides.yaml.tmpl +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/traceability.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/watch/__init__.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/watch/events.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/watch/propagation_log.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/watch/propagation_pipeline.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/watch/test_runner.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/watch/watcher.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd/wiring.py +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ai_governance_eu_act/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ai_governance_eu_act/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ai_governance_eu_act/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ai_governance_eu_act/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ai_governance_eu_act/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ai_governance_eu_act/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/api_rate_limiting_caching/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/api_rate_limiting_caching/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/api_rate_limiting_caching/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/api_rate_limiting_caching/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/api_rate_limiting_caching/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/api_rate_limiting_caching/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/api_rest_openapi/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/api_rest_openapi/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/api_rest_openapi/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/api_rest_openapi/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/api_rest_openapi/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/api_rest_openapi/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/babok/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/babok/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/babok/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/babok/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/babok/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_event_cloudevents/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_event_cloudevents/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_event_cloudevents/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_event_cloudevents/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_event_cloudevents/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_event_cloudevents/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_graphql/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_graphql/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_graphql/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_graphql/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_graphql/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_graphql/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_grpc_proto/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_grpc_proto/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_grpc_proto/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_grpc_proto/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_grpc_proto/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/backend_grpc_proto/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_hipaa/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_hipaa/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_hipaa/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_hipaa/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_hipaa/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_hipaa/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_iso27001/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_iso27001/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_iso27001/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_iso27001/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_iso27001/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_iso27001/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_pci_dss_4/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_pci_dss_4/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_pci_dss_4/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_pci_dss_4/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_pci_dss_4/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/compliance_pci_dss_4/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_governance_appi_gdpr/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_governance_appi_gdpr/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_governance_appi_gdpr/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_governance_appi_gdpr/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_governance_appi_gdpr/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_governance_appi_gdpr/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_nosql_jsonschema/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_nosql_jsonschema/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_nosql_jsonschema/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_nosql_jsonschema/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_nosql_jsonschema/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_nosql_jsonschema/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_relational_iso_sql/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_relational_iso_sql/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_relational_iso_sql/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_relational_iso_sql/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_relational_iso_sql/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/data_relational_iso_sql/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ddd_domain_driven_design/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ddd_domain_driven_design/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ddd_domain_driven_design/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ddd_domain_driven_design/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ddd_domain_driven_design/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ddd_domain_driven_design/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/dora_sre_metrics/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/dora_sre_metrics/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/dora_sre_metrics/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/dora_sre_metrics/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/dora_sre_metrics/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/dora_sre_metrics/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/i18n_unicode_cldr/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/i18n_unicode_cldr/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/i18n_unicode_cldr/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/i18n_unicode_cldr/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/i18n_unicode_cldr/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/i18n_unicode_cldr/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ml_model_cards/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ml_model_cards/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ml_model_cards/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ml_model_cards/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ml_model_cards/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ml_model_cards/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_a11y_native/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_a11y_native/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_a11y_native/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_a11y_native/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_a11y_native/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_a11y_native/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_android_material3/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_android_material3/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_android_material3/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_android_material3/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_android_material3/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_android_material3/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_ios_hig/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_ios_hig/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_ios_hig/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_ios_hig/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_ios_hig/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_ios_hig/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_security_masvs/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_security_masvs/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_security_masvs/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_security_masvs/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_security_masvs/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/mobile_security_masvs/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_cicd_pipeline/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_cicd_pipeline/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_cicd_pipeline/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_cicd_pipeline/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_cicd_pipeline/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_cicd_pipeline/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_iac_terraform/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_iac_terraform/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_iac_terraform/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_iac_terraform/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_iac_terraform/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_iac_terraform/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_kubernetes/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_kubernetes/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_kubernetes/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_kubernetes/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_kubernetes/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_kubernetes/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_observability_otel/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_observability_otel/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_observability_otel/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_observability_otel/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_observability_otel/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/ops_observability_otel/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/process_iso25010/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/process_iso25010/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/process_iso25010/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/process_iso25010/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/process_iso25010/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/process_iso25010/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/process_test_iso29119/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/process_test_iso29119/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/process_test_iso29119/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/process_test_iso29119/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/process_test_iso29119/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/process_test_iso29119/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/twelve_factor_app/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/twelve_factor_app/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/twelve_factor_app/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/twelve_factor_app/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/twelve_factor_app/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/twelve_factor_app/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_authn_webauthn/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_authn_webauthn/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_authn_webauthn/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_authn_webauthn/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_authn_webauthn/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_authn_webauthn/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_browser_compat/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_browser_compat/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_browser_compat/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_browser_compat/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_browser_compat/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_browser_compat/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_forms_html5/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_forms_html5/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_forms_html5/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_forms_html5/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_forms_html5/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_forms_html5/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_performance_core_web_vitals/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_performance_core_web_vitals/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_performance_core_web_vitals/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_performance_core_web_vitals/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_performance_core_web_vitals/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_performance_core_web_vitals/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_pwa_manifest/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_pwa_manifest/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_pwa_manifest/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_pwa_manifest/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_pwa_manifest/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_pwa_manifest/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_responsive/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_responsive/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_responsive/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_responsive/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_responsive/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_responsive/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_security_owasp/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_security_owasp/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_security_owasp/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_security_owasp/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_security_owasp/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_security_owasp/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_seo_schemaorg/coverage_matrix.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_seo_schemaorg/elicit_extend.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_seo_schemaorg/lexicon.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_seo_schemaorg/manifest.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_seo_schemaorg/recommended_kinds.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/codd_plugins/lexicons/web_seo_schemaorg/severity_rules.yaml +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/docs/cookbook/cdp_browser/README.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/docs/requirements/README.md +0 -0
- {codd_dev-2.11.0 → codd_dev-2.13.0}/tests/integration/standalone_repair_skeleton/README.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codd-dev
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.13.0
|
|
4
4
|
Summary: CoDD: Coherence-Driven Development — cross-artifact change impact analysis
|
|
5
5
|
Project-URL: Homepage, https://github.com/yohey-w/codd-dev
|
|
6
6
|
Project-URL: Repository, https://github.com/yohey-w/codd-dev
|
|
@@ -153,8 +153,11 @@ This is what lets CoDD ship one core that works for Next.js, Django, FastAPI, Ra
|
|
|
153
153
|
|
|
154
154
|
## 🧭 Roadmap
|
|
155
155
|
|
|
156
|
-
- **v2.
|
|
157
|
-
- **v2.
|
|
156
|
+
- **v2.13.0 (current)** — Opt-out protection: `OptOutPolicy` requires a `justification` + `expires_at` for every config-level opt-out (`ci.provider=none`, etc.). Silent SKIP abolished; severity preserved. `codd validate` reports policy violations. See [post-mortem](docs/post-mortems/optout_loophole.md).
|
|
157
|
+
- **v2.12.0** — Test-completeness gates: C7 `actors_without_journeys` amber promotion + new C8 `ci_health` static check (workflow presence, trigger coverage, verification-in-workflow). See [post-mortem](docs/post-mortems/test_completeness_gap.md).
|
|
158
|
+
- **v2.11.0** — Sprint-less `codd implement` (`--design <path> --output <dir>` directly; `implementation_plan.md` parser removed). See [migration guide](docs/migrations/v2.11.0-sprintless.md).
|
|
159
|
+
- **v2.10.0** — Lexicon-driven completeness, 38 plug-ins, LLM-enhanced init, scope/phase filter, auto-repair across the full DAG.
|
|
160
|
+
- **v2.14.0 (next)** — C8 `ci_health` runtime mode (opt-in `ci.runtime_check: true`) polling the CI provider for latest-run-on-default-branch success.
|
|
158
161
|
|
|
159
162
|
---
|
|
160
163
|
|
|
@@ -113,8 +113,11 @@ This is what lets CoDD ship one core that works for Next.js, Django, FastAPI, Ra
|
|
|
113
113
|
|
|
114
114
|
## 🧭 Roadmap
|
|
115
115
|
|
|
116
|
-
- **v2.
|
|
117
|
-
- **v2.
|
|
116
|
+
- **v2.13.0 (current)** — Opt-out protection: `OptOutPolicy` requires a `justification` + `expires_at` for every config-level opt-out (`ci.provider=none`, etc.). Silent SKIP abolished; severity preserved. `codd validate` reports policy violations. See [post-mortem](docs/post-mortems/optout_loophole.md).
|
|
117
|
+
- **v2.12.0** — Test-completeness gates: C7 `actors_without_journeys` amber promotion + new C8 `ci_health` static check (workflow presence, trigger coverage, verification-in-workflow). See [post-mortem](docs/post-mortems/test_completeness_gap.md).
|
|
118
|
+
- **v2.11.0** — Sprint-less `codd implement` (`--design <path> --output <dir>` directly; `implementation_plan.md` parser removed). See [migration guide](docs/migrations/v2.11.0-sprintless.md).
|
|
119
|
+
- **v2.10.0** — Lexicon-driven completeness, 38 plug-ins, LLM-enhanced init, scope/phase filter, auto-repair across the full DAG.
|
|
120
|
+
- **v2.14.0 (next)** — C8 `ci_health` runtime mode (opt-in `ci.runtime_check: true`) polling the CI provider for latest-run-on-default-branch success.
|
|
118
121
|
|
|
119
122
|
---
|
|
120
123
|
|
|
@@ -4901,10 +4901,13 @@ def dag_verify(project_path: str, check_names: tuple[str, ...], output_format: s
|
|
|
4901
4901
|
click.echo(f"Error: {exc}")
|
|
4902
4902
|
raise SystemExit(1)
|
|
4903
4903
|
|
|
4904
|
+
opt_out_results = [result for result in results if _dag_result_status(result) == "opt_out"]
|
|
4904
4905
|
failed_red = [
|
|
4905
4906
|
result
|
|
4906
4907
|
for result in results
|
|
4907
|
-
if not _dag_result_passed(result)
|
|
4908
|
+
if not _dag_result_passed(result)
|
|
4909
|
+
and _dag_result_severity(result) == "red"
|
|
4910
|
+
and _dag_result_status(result) != "opt_out"
|
|
4908
4911
|
]
|
|
4909
4912
|
amber_findings = [
|
|
4910
4913
|
result
|
|
@@ -4917,7 +4920,10 @@ def dag_verify(project_path: str, check_names: tuple[str, ...], output_format: s
|
|
|
4917
4920
|
else:
|
|
4918
4921
|
for result in results:
|
|
4919
4922
|
severity = _dag_result_severity(result)
|
|
4920
|
-
|
|
4923
|
+
status_value = _dag_result_status(result)
|
|
4924
|
+
if status_value == "opt_out":
|
|
4925
|
+
status = "OPT_OUT"
|
|
4926
|
+
elif _dag_result_passed(result):
|
|
4921
4927
|
status = "PASS"
|
|
4922
4928
|
else:
|
|
4923
4929
|
status = "WARN" if severity == "amber" else "FAIL"
|
|
@@ -4929,6 +4935,10 @@ def dag_verify(project_path: str, check_names: tuple[str, ...], output_format: s
|
|
|
4929
4935
|
click.echo(f"\n{len(failed_red)} check(s) FAILED (severity=red)")
|
|
4930
4936
|
elif amber_findings:
|
|
4931
4937
|
click.echo(f"\n{len(amber_findings)} check(s) WARN (severity=amber, deploy allowed)")
|
|
4938
|
+
if opt_out_results:
|
|
4939
|
+
click.echo(f"\n{len(opt_out_results)} active opt-out(s) (deploy allowed):")
|
|
4940
|
+
for result in opt_out_results:
|
|
4941
|
+
click.echo(f" - {_dag_result_name(result)}: {_dag_result_message(result)}")
|
|
4932
4942
|
|
|
4933
4943
|
raise SystemExit(1 if failed_red else 0)
|
|
4934
4944
|
|
|
@@ -5185,6 +5195,14 @@ def _dag_result_passed(result: Any) -> bool:
|
|
|
5185
5195
|
return _dag_result_value(result, "passed") is not False
|
|
5186
5196
|
|
|
5187
5197
|
|
|
5198
|
+
def _dag_result_status(result: Any) -> str:
|
|
5199
|
+
return str(_dag_result_value(result, "status") or "")
|
|
5200
|
+
|
|
5201
|
+
|
|
5202
|
+
def _dag_result_message(result: Any) -> str:
|
|
5203
|
+
return str(_dag_result_value(result, "message") or "")
|
|
5204
|
+
|
|
5205
|
+
|
|
5188
5206
|
def _dag_result_has_findings(result: Any) -> bool:
|
|
5189
5207
|
for key in (
|
|
5190
5208
|
"violations",
|
|
@@ -183,12 +183,17 @@ def compute_dag_completeness(
|
|
|
183
183
|
return _exception_result("dag_completeness", threshold, exc)
|
|
184
184
|
|
|
185
185
|
red_results = [result for result in results if _dag_result_severity(result) == "red"]
|
|
186
|
-
failed_red = [
|
|
186
|
+
failed_red = [
|
|
187
|
+
result
|
|
188
|
+
for result in red_results
|
|
189
|
+
if _dag_result_passed(result) is False and _dag_result_status(result) != "opt_out"
|
|
190
|
+
]
|
|
187
191
|
amber_findings = [
|
|
188
192
|
result
|
|
189
193
|
for result in results
|
|
190
194
|
if _dag_result_severity(result) == "amber" and _dag_result_has_findings(result)
|
|
191
195
|
]
|
|
196
|
+
opt_outs = [result for result in results if _dag_result_status(result) == "opt_out"]
|
|
192
197
|
|
|
193
198
|
total = len(red_results)
|
|
194
199
|
uncovered = len(failed_red)
|
|
@@ -197,6 +202,7 @@ def compute_dag_completeness(
|
|
|
197
202
|
details = [f"checks: {len(results)}", f"red_failures: {uncovered}"]
|
|
198
203
|
details.extend(_format_dag_result(result) for result in failed_red[:5])
|
|
199
204
|
details.extend(f"warning: {_format_dag_result(result)}" for result in amber_findings[:5])
|
|
205
|
+
details.extend(f"opt_out: {_format_dag_result(result)}" for result in opt_outs[:5])
|
|
200
206
|
|
|
201
207
|
return CoverageResult(
|
|
202
208
|
metric="dag_completeness",
|
|
@@ -361,6 +367,10 @@ def _dag_result_passed(result: Any) -> bool:
|
|
|
361
367
|
return _dag_result_value(result, "passed") is not False
|
|
362
368
|
|
|
363
369
|
|
|
370
|
+
def _dag_result_status(result: Any) -> str:
|
|
371
|
+
return str(_dag_result_value(result, "status") or "")
|
|
372
|
+
|
|
373
|
+
|
|
364
374
|
def _dag_result_name(result: Any) -> str:
|
|
365
375
|
return str(_dag_result_value(result, "check_name") or result.__class__.__name__)
|
|
366
376
|
|
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from dataclasses import dataclass
|
|
6
|
+
from datetime import date
|
|
6
7
|
from pathlib import Path
|
|
7
|
-
from typing import Any
|
|
8
|
+
from typing import Any, TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from codd.dag.checks.opt_out import OptOutDeclaration, OptOutPolicy, OptOutSignal
|
|
8
12
|
|
|
9
13
|
|
|
10
14
|
_REGISTRY: dict[str, type[Any]] = {}
|
|
@@ -34,14 +38,50 @@ class DagCheck:
|
|
|
34
38
|
dag: Any | None = None,
|
|
35
39
|
project_root: str | Path | None = None,
|
|
36
40
|
settings: dict[str, Any] | None = None,
|
|
41
|
+
opt_out_policy: "OptOutPolicy | None" = None,
|
|
42
|
+
today: date | None = None,
|
|
37
43
|
) -> None:
|
|
38
44
|
self.dag = dag
|
|
39
45
|
self.project_root = Path(project_root) if project_root is not None else None
|
|
40
46
|
self.settings = settings or {}
|
|
47
|
+
self.opt_out_policy = opt_out_policy
|
|
48
|
+
self.today = today or date.today()
|
|
41
49
|
|
|
42
50
|
def run(self, dag: Any | None = None) -> CheckResult:
|
|
43
51
|
raise NotImplementedError
|
|
44
52
|
|
|
53
|
+
def detect_opt_out(self, codd_config: dict[str, Any]) -> "OptOutSignal | None":
|
|
54
|
+
"""Return an OptOutSignal when this check's config requests an opt-out.
|
|
55
|
+
|
|
56
|
+
Default: no opt-out detection. Subclasses that own a config-level
|
|
57
|
+
opt-out flag (e.g. ``ci.provider: none``) override this and route the
|
|
58
|
+
request through :class:`OptOutPolicy` rather than handling it inline.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
del codd_config
|
|
62
|
+
return None
|
|
63
|
+
|
|
64
|
+
def resolve_opt_out(
|
|
65
|
+
self,
|
|
66
|
+
codd_config: dict[str, Any] | None = None,
|
|
67
|
+
) -> "tuple[OptOutSignal, OptOutDeclaration | None] | None":
|
|
68
|
+
"""Convenience helper: run detect_opt_out and look up a declaration.
|
|
69
|
+
|
|
70
|
+
Returns ``None`` when no opt-out signal is detected. Returns
|
|
71
|
+
``(signal, declaration_or_None)`` otherwise so the caller can decide
|
|
72
|
+
whether the missing-or-expired declaration should fail red or pass
|
|
73
|
+
through.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
config = codd_config if codd_config is not None else self.settings
|
|
77
|
+
signal = self.detect_opt_out(config)
|
|
78
|
+
if signal is None:
|
|
79
|
+
return None
|
|
80
|
+
declaration = (
|
|
81
|
+
self.opt_out_policy.lookup(signal.check_name) if self.opt_out_policy else None
|
|
82
|
+
)
|
|
83
|
+
return signal, declaration
|
|
84
|
+
|
|
45
85
|
|
|
46
86
|
def register_dag_check(name: str):
|
|
47
87
|
"""Register a DAG check class under ``name``."""
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
"""C8 CI health check with deterministic static validation."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import asdict, dataclass, field
|
|
6
|
+
from glob import glob
|
|
7
|
+
import json
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import re
|
|
10
|
+
from typing import Any, Mapping
|
|
11
|
+
|
|
12
|
+
import yaml
|
|
13
|
+
|
|
14
|
+
from codd.dag.checks import DagCheck, register_dag_check
|
|
15
|
+
from codd.dag.checks.opt_out import (
|
|
16
|
+
OPT_OUT_STATUS,
|
|
17
|
+
OptOutDeclaration,
|
|
18
|
+
OptOutSignal,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
_DEFAULT_PROVIDER = "github" + "_actions"
|
|
23
|
+
_OPT_OUT_PROVIDER = "none"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class CiConfig:
|
|
28
|
+
provider: str = _DEFAULT_PROVIDER
|
|
29
|
+
workflow_glob: str = ".github/workflows/*.yml"
|
|
30
|
+
required_triggers: list[str] = field(default_factory=lambda: ["push", "pull_request"])
|
|
31
|
+
runtime_check: bool = False
|
|
32
|
+
staleness_days: int = 14
|
|
33
|
+
default_branch: str = "main"
|
|
34
|
+
trigger_key: str = "on"
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def from_mapping(cls, value: Mapping[str, Any] | None) -> "CiConfig":
|
|
38
|
+
if not isinstance(value, Mapping):
|
|
39
|
+
# Missing ``ci:`` section is no longer treated as a silent opt-out.
|
|
40
|
+
# The default provider applies; if no workflow files exist this
|
|
41
|
+
# surfaces as a normal red ``ci_workflow_missing`` finding rather
|
|
42
|
+
# than a free PASS.
|
|
43
|
+
return cls()
|
|
44
|
+
|
|
45
|
+
config = cls()
|
|
46
|
+
return cls(
|
|
47
|
+
provider=_string_value(value.get("provider"), config.provider),
|
|
48
|
+
workflow_glob=_string_value(value.get("workflow_glob"), config.workflow_glob),
|
|
49
|
+
required_triggers=_string_list(value.get("required_triggers"), config.required_triggers),
|
|
50
|
+
runtime_check=bool(value.get("runtime_check", config.runtime_check)),
|
|
51
|
+
staleness_days=_int_value(value.get("staleness_days"), config.staleness_days),
|
|
52
|
+
default_branch=_string_value(value.get("default_branch"), config.default_branch),
|
|
53
|
+
trigger_key=_string_value(value.get("trigger_key"), config.trigger_key),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass
|
|
58
|
+
class CiHealthFinding:
|
|
59
|
+
violation_type: str
|
|
60
|
+
severity: str
|
|
61
|
+
block_deploy: bool
|
|
62
|
+
message: str
|
|
63
|
+
details: list[str] = field(default_factory=list)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass
|
|
67
|
+
class CiHealthResult:
|
|
68
|
+
check_name: str = "ci_health"
|
|
69
|
+
status: str = "pass"
|
|
70
|
+
severity: str = "info"
|
|
71
|
+
block_deploy: bool = False
|
|
72
|
+
message: str = "C8 ci_health PASS"
|
|
73
|
+
findings: list[CiHealthFinding] = field(default_factory=list)
|
|
74
|
+
workflow_files: list[str] = field(default_factory=list)
|
|
75
|
+
passed: bool = True
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@register_dag_check("ci_health")
|
|
79
|
+
class CiHealthCheck(DagCheck):
|
|
80
|
+
"""C8 CI workflow presence and trigger validation.
|
|
81
|
+
|
|
82
|
+
Runtime provider polling is intentionally deferred. The shipped path is
|
|
83
|
+
static, deterministic, and driven by config values.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
check_name = "ci_health"
|
|
87
|
+
severity = "red"
|
|
88
|
+
block_deploy = True
|
|
89
|
+
|
|
90
|
+
def run(
|
|
91
|
+
self,
|
|
92
|
+
dag: Any | None = None,
|
|
93
|
+
project_root: str | Path | None = None,
|
|
94
|
+
settings: dict[str, Any] | None = None,
|
|
95
|
+
codd_config: dict[str, Any] | None = None,
|
|
96
|
+
) -> CiHealthResult:
|
|
97
|
+
del dag
|
|
98
|
+
root = Path(project_root or self.project_root or ".").resolve()
|
|
99
|
+
active_settings = codd_config or settings or self.settings
|
|
100
|
+
config = CiConfig.from_mapping(_mapping_value(active_settings, "ci"))
|
|
101
|
+
return self.check(root, config)
|
|
102
|
+
|
|
103
|
+
def detect_opt_out(self, codd_config: dict[str, Any]) -> OptOutSignal | None:
|
|
104
|
+
config = CiConfig.from_mapping(_mapping_value(codd_config, "ci"))
|
|
105
|
+
if self._is_opt_out_provider(config):
|
|
106
|
+
return OptOutSignal(
|
|
107
|
+
check_name=self.check_name,
|
|
108
|
+
source="ci.provider=none",
|
|
109
|
+
)
|
|
110
|
+
return None
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def _is_opt_out_provider(config: CiConfig) -> bool:
|
|
114
|
+
return config.provider.strip().lower() == _OPT_OUT_PROVIDER
|
|
115
|
+
|
|
116
|
+
def _make_opt_out_result(self, declaration: OptOutDeclaration | None) -> CiHealthResult:
|
|
117
|
+
today = self.today
|
|
118
|
+
if declaration is None:
|
|
119
|
+
return CiHealthResult(
|
|
120
|
+
status="fail",
|
|
121
|
+
severity="red",
|
|
122
|
+
block_deploy=True,
|
|
123
|
+
message=(
|
|
124
|
+
"C8 ci_health: ci.provider=none requires an opt_outs declaration "
|
|
125
|
+
"in codd.yaml (check: ci_health, reason: ..., expires_at: "
|
|
126
|
+
"YYYY-MM-DD)."
|
|
127
|
+
),
|
|
128
|
+
passed=False,
|
|
129
|
+
)
|
|
130
|
+
if declaration.is_expired(today):
|
|
131
|
+
return CiHealthResult(
|
|
132
|
+
status="fail",
|
|
133
|
+
severity="red",
|
|
134
|
+
block_deploy=True,
|
|
135
|
+
message=(
|
|
136
|
+
f"C8 ci_health: opt-out expired on "
|
|
137
|
+
f"{declaration.expires_at.isoformat()} "
|
|
138
|
+
f"(reason: {declaration.reason}); renew the entry or remove it."
|
|
139
|
+
),
|
|
140
|
+
passed=False,
|
|
141
|
+
)
|
|
142
|
+
return CiHealthResult(
|
|
143
|
+
status=OPT_OUT_STATUS,
|
|
144
|
+
severity=self.severity,
|
|
145
|
+
block_deploy=False,
|
|
146
|
+
message=(
|
|
147
|
+
f"C8 ci_health opt-out active "
|
|
148
|
+
f"(reason: {declaration.reason}, "
|
|
149
|
+
f"expires: {declaration.expires_at.isoformat()})"
|
|
150
|
+
),
|
|
151
|
+
passed=False,
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
def check(self, project_root: Path, config: CiConfig) -> CiHealthResult:
|
|
155
|
+
project_root = Path(project_root).resolve()
|
|
156
|
+
if self._is_opt_out_provider(config):
|
|
157
|
+
declaration = (
|
|
158
|
+
self.opt_out_policy.lookup(self.check_name) if self.opt_out_policy else None
|
|
159
|
+
)
|
|
160
|
+
return self._make_opt_out_result(declaration)
|
|
161
|
+
workflow_files = self._locate_workflows(project_root, config.workflow_glob)
|
|
162
|
+
if not workflow_files:
|
|
163
|
+
finding = CiHealthFinding(
|
|
164
|
+
violation_type="ci_workflow_missing",
|
|
165
|
+
severity="red",
|
|
166
|
+
block_deploy=True,
|
|
167
|
+
message="No CI workflow files found matching glob.",
|
|
168
|
+
details=[config.workflow_glob],
|
|
169
|
+
)
|
|
170
|
+
return CiHealthResult(
|
|
171
|
+
status="fail",
|
|
172
|
+
severity="red",
|
|
173
|
+
block_deploy=True,
|
|
174
|
+
message=finding.message,
|
|
175
|
+
findings=[finding],
|
|
176
|
+
passed=False,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
findings = [
|
|
180
|
+
*self._check_triggers(workflow_files, config.required_triggers, config.trigger_key),
|
|
181
|
+
*self._check_verification_coverage(workflow_files, project_root),
|
|
182
|
+
]
|
|
183
|
+
block_deploy = any(finding.block_deploy for finding in findings)
|
|
184
|
+
severity = _max_severity(finding.severity for finding in findings)
|
|
185
|
+
status = "fail" if block_deploy else ("warn" if findings else "pass")
|
|
186
|
+
message = (
|
|
187
|
+
"C8 ci_health PASS"
|
|
188
|
+
if not findings
|
|
189
|
+
else f"C8 ci_health found {len(findings)} static finding(s)"
|
|
190
|
+
)
|
|
191
|
+
return CiHealthResult(
|
|
192
|
+
status=status,
|
|
193
|
+
severity=severity,
|
|
194
|
+
block_deploy=block_deploy,
|
|
195
|
+
message=message,
|
|
196
|
+
findings=findings,
|
|
197
|
+
workflow_files=[path.relative_to(project_root).as_posix() for path in workflow_files],
|
|
198
|
+
passed=not block_deploy,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
def format_report(self, result: CiHealthResult) -> str:
|
|
202
|
+
return json.dumps({"ci_health_report": asdict(result)}, ensure_ascii=False, indent=2)
|
|
203
|
+
|
|
204
|
+
def _locate_workflows(self, project_root: Path, workflow_glob: str) -> list[Path]:
|
|
205
|
+
pattern = workflow_glob.strip()
|
|
206
|
+
if not pattern:
|
|
207
|
+
return []
|
|
208
|
+
if Path(pattern).is_absolute():
|
|
209
|
+
paths = [Path(path) for path in glob(pattern)]
|
|
210
|
+
else:
|
|
211
|
+
paths = list(project_root.glob(pattern))
|
|
212
|
+
return sorted(path for path in paths if path.is_file())
|
|
213
|
+
|
|
214
|
+
def _check_triggers(
|
|
215
|
+
self,
|
|
216
|
+
workflow_files: list[Path],
|
|
217
|
+
required_triggers: list[str],
|
|
218
|
+
trigger_key: str,
|
|
219
|
+
) -> list[CiHealthFinding]:
|
|
220
|
+
required = {trigger.strip() for trigger in required_triggers if trigger.strip()}
|
|
221
|
+
if not required:
|
|
222
|
+
return []
|
|
223
|
+
|
|
224
|
+
actual: set[str] = set()
|
|
225
|
+
for path in workflow_files:
|
|
226
|
+
actual.update(self._workflow_triggers(path, trigger_key))
|
|
227
|
+
|
|
228
|
+
missing = sorted(required - actual)
|
|
229
|
+
if not missing:
|
|
230
|
+
return []
|
|
231
|
+
return [
|
|
232
|
+
CiHealthFinding(
|
|
233
|
+
violation_type="ci_trigger_incomplete",
|
|
234
|
+
severity="amber",
|
|
235
|
+
block_deploy=False,
|
|
236
|
+
message="CI workflow does not include all required triggers.",
|
|
237
|
+
details=[f"missing: {', '.join(missing)}"],
|
|
238
|
+
)
|
|
239
|
+
]
|
|
240
|
+
|
|
241
|
+
def _workflow_triggers(self, path: Path, trigger_key: str) -> set[str]:
|
|
242
|
+
payload = _read_yaml_mapping(path)
|
|
243
|
+
value = payload.get(trigger_key)
|
|
244
|
+
if value is None and trigger_key == "on":
|
|
245
|
+
value = payload.get(True)
|
|
246
|
+
return _trigger_names(value)
|
|
247
|
+
|
|
248
|
+
def _check_verification_coverage(
|
|
249
|
+
self,
|
|
250
|
+
workflow_files: list[Path],
|
|
251
|
+
project_root: Path,
|
|
252
|
+
) -> list[CiHealthFinding]:
|
|
253
|
+
verification_commands = self._deploy_verification_commands(project_root)
|
|
254
|
+
if not verification_commands:
|
|
255
|
+
return []
|
|
256
|
+
|
|
257
|
+
workflow_commands = {
|
|
258
|
+
_normalize_command(command)
|
|
259
|
+
for path in workflow_files
|
|
260
|
+
for command in self._workflow_commands(path)
|
|
261
|
+
if _normalize_command(command)
|
|
262
|
+
}
|
|
263
|
+
missing = [
|
|
264
|
+
command
|
|
265
|
+
for command in verification_commands
|
|
266
|
+
if not self._command_appears_in_workflow(command, workflow_commands)
|
|
267
|
+
]
|
|
268
|
+
if not missing:
|
|
269
|
+
return []
|
|
270
|
+
return [
|
|
271
|
+
CiHealthFinding(
|
|
272
|
+
violation_type="ci_verification_not_in_workflow",
|
|
273
|
+
severity="amber",
|
|
274
|
+
block_deploy=False,
|
|
275
|
+
message="Deployment verification command is not invoked by CI workflow.",
|
|
276
|
+
details=missing,
|
|
277
|
+
)
|
|
278
|
+
]
|
|
279
|
+
|
|
280
|
+
def _deploy_verification_commands(self, project_root: Path) -> list[str]:
|
|
281
|
+
commands: list[str] = []
|
|
282
|
+
for path in self._deploy_yaml_candidates(project_root):
|
|
283
|
+
if not path.is_file():
|
|
284
|
+
continue
|
|
285
|
+
payload = _read_yaml_mapping(path)
|
|
286
|
+
commands.extend(_hook_commands(payload))
|
|
287
|
+
return _dedupe(_normalize_command(command) for command in commands if _normalize_command(command))
|
|
288
|
+
|
|
289
|
+
@staticmethod
|
|
290
|
+
def _deploy_yaml_candidates(project_root: Path) -> list[Path]:
|
|
291
|
+
return [
|
|
292
|
+
project_root / "deploy.yaml",
|
|
293
|
+
project_root / ".codd" / "deploy.yaml",
|
|
294
|
+
project_root / "codd" / "deploy.yaml",
|
|
295
|
+
]
|
|
296
|
+
|
|
297
|
+
def _workflow_commands(self, path: Path) -> list[str]:
|
|
298
|
+
return _command_values(_read_yaml_mapping(path))
|
|
299
|
+
|
|
300
|
+
@staticmethod
|
|
301
|
+
def _command_appears_in_workflow(command: str, workflow_commands: set[str]) -> bool:
|
|
302
|
+
return any(command == candidate or command in candidate for candidate in workflow_commands)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def _read_yaml_mapping(path: Path) -> dict[str, Any]:
|
|
306
|
+
payload = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
|
|
307
|
+
return payload if isinstance(payload, dict) else {}
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def _mapping_value(mapping: Any, key: str) -> Mapping[str, Any] | None:
|
|
311
|
+
if isinstance(mapping, Mapping) and isinstance(mapping.get(key), Mapping):
|
|
312
|
+
return mapping[key]
|
|
313
|
+
return None
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def _trigger_names(value: Any) -> set[str]:
|
|
317
|
+
if isinstance(value, str):
|
|
318
|
+
return {value}
|
|
319
|
+
if isinstance(value, list):
|
|
320
|
+
return {str(item) for item in value if item}
|
|
321
|
+
if isinstance(value, dict):
|
|
322
|
+
return {str(key) for key in value if key}
|
|
323
|
+
return set()
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def _hook_commands(value: Any) -> list[str]:
|
|
327
|
+
if isinstance(value, str):
|
|
328
|
+
return [value]
|
|
329
|
+
if isinstance(value, list):
|
|
330
|
+
commands: list[str] = []
|
|
331
|
+
for item in value:
|
|
332
|
+
commands.extend(_hook_commands(item))
|
|
333
|
+
return commands
|
|
334
|
+
if isinstance(value, dict):
|
|
335
|
+
commands: list[str] = []
|
|
336
|
+
for key in ("post_deploy", "post_deploy_steps", "post_deploy_hooks", "verification", "verifications"):
|
|
337
|
+
commands.extend(_hook_commands(value.get(key)))
|
|
338
|
+
for key in ("command", "run", "script", "test"):
|
|
339
|
+
commands.extend(_hook_commands(value.get(key)))
|
|
340
|
+
targets = value.get("targets")
|
|
341
|
+
if isinstance(targets, dict):
|
|
342
|
+
for target_config in targets.values():
|
|
343
|
+
commands.extend(_hook_commands(target_config))
|
|
344
|
+
return commands
|
|
345
|
+
return []
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def _command_values(value: Any) -> list[str]:
|
|
349
|
+
if isinstance(value, str):
|
|
350
|
+
return []
|
|
351
|
+
if isinstance(value, list):
|
|
352
|
+
commands: list[str] = []
|
|
353
|
+
for item in value:
|
|
354
|
+
commands.extend(_command_values(item))
|
|
355
|
+
return commands
|
|
356
|
+
if isinstance(value, dict):
|
|
357
|
+
commands: list[str] = []
|
|
358
|
+
for key, item in value.items():
|
|
359
|
+
if key in {"run", "script", "command", "commands"}:
|
|
360
|
+
commands.extend(_coerce_command_list(item))
|
|
361
|
+
else:
|
|
362
|
+
commands.extend(_command_values(item))
|
|
363
|
+
return commands
|
|
364
|
+
return []
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def _coerce_command_list(value: Any) -> list[str]:
|
|
368
|
+
if isinstance(value, str):
|
|
369
|
+
return [value]
|
|
370
|
+
if isinstance(value, list):
|
|
371
|
+
commands: list[str] = []
|
|
372
|
+
for item in value:
|
|
373
|
+
commands.extend(_coerce_command_list(item))
|
|
374
|
+
return commands
|
|
375
|
+
return []
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def _normalize_command(value: str) -> str:
|
|
379
|
+
return re.sub(r"\s+", " ", value).strip()
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def _dedupe(values: Any) -> list[str]:
|
|
383
|
+
seen: set[str] = set()
|
|
384
|
+
result: list[str] = []
|
|
385
|
+
for value in values:
|
|
386
|
+
if not value or value in seen:
|
|
387
|
+
continue
|
|
388
|
+
seen.add(value)
|
|
389
|
+
result.append(value)
|
|
390
|
+
return result
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def _string_value(value: Any, default: str) -> str:
|
|
394
|
+
return value if isinstance(value, str) and value.strip() else default
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def _string_list(value: Any, default: list[str]) -> list[str]:
|
|
398
|
+
if not isinstance(value, list):
|
|
399
|
+
return list(default)
|
|
400
|
+
result = [str(item) for item in value if str(item).strip()]
|
|
401
|
+
return result or list(default)
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def _int_value(value: Any, default: int) -> int:
|
|
405
|
+
try:
|
|
406
|
+
return int(value)
|
|
407
|
+
except (TypeError, ValueError):
|
|
408
|
+
return default
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def _max_severity(values: Any) -> str:
|
|
412
|
+
order = {"info": 0, "amber": 1, "red": 2}
|
|
413
|
+
selected = "info"
|
|
414
|
+
for value in values:
|
|
415
|
+
text = str(value)
|
|
416
|
+
if order.get(text, 0) > order[selected]:
|
|
417
|
+
selected = text
|
|
418
|
+
return selected
|