codd-dev 2.1.0__tar.gz → 2.3.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.1.0 → codd_dev-2.3.0}/PKG-INFO +1 -1
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/builder.py +23 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/extractor.py +42 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/elicit/apply.py +161 -15
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/elicit/engine.py +174 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/elicit/lexicon_loader.py +28 -1
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/lexicon.py +14 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/templates/extracted/schema-design.md.j2 +1 -1
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/templates/lexicon_schema.yaml +2 -0
- codd_dev-2.3.0/codd_plugins/lexicons/babok/lexicon.yaml +105 -0
- codd_dev-2.3.0/codd_plugins/lexicons/babok/severity_rules.yaml +53 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/pyproject.toml +1 -1
- {codd_dev-2.1.0 → codd_dev-2.3.0}/.gitignore +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/LICENSE +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/README.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/__main__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/_git_helper.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/ask_user_question_adapter.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/assembler.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/bridge.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/brownfield/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/brownfield/pipeline.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/cli.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/clustering.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/coherence_adapters.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/coherence_engine.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/config.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/contracts.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/coverage_auditor.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/coverage_metrics.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/checks/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/checks/depends_on_consistency.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/checks/deployment_completeness.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/checks/edge_validity.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/checks/environment_coverage.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/checks/implementation_coverage.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/checks/node_completeness.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/checks/task_completion.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/checks/transitive_closure.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/checks/user_journey_coherence.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/coverage_axes.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/defaults/cli.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/defaults/cpp_embedded.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/defaults/csharp.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/defaults/elixir.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/defaults/generic.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/defaults/iot.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/defaults/java.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/defaults/kotlin.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/defaults/mobile.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/defaults/ruby.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/defaults/rust.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/defaults/scala.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/defaults/swift.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/defaults/test_frameworks.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/defaults/web.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/extractor.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/dag/runner.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/defaults.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deploy_targets/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deploy_targets/app_service.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deploy_targets/base.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deploy_targets/docker_compose.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployer.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/checks/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/defaults/deploy_targets.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/defaults/runtime_capability_inference.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/defaults/schema_providers.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/defaults/verification_templates.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/ai_command.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/llm_consideration.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/schema/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/schema/prisma.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/target/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/target/docker_compose.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/verification/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/verification/assertion_handlers.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/verification/cdp_browser.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/verification/cdp_engines.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/verification/cdp_launchers.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/verification/cdp_wire.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/verification/curl.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/verification/form_strategies.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/verification/means_catalog.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/deployment/providers/verification/playwright.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/design_md.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/diff/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/diff/apply.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/diff/engine.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/diff/persistence.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/diff/templates/diff_prompt.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/drift.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/e2e_extractor.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/e2e_generator.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/e2e_runner.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/elicit/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/elicit/finding.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/elicit/formatters/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/elicit/formatters/base.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/elicit/formatters/interactive.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/elicit/formatters/json_fmt.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/elicit/formatters/md.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/elicit/persistence.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/elicit/templates/elicit_prompt_L0.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/env_refs.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/extract_ai.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/extractor.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/fixer.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/fixup_drift.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/fixup_drift_strategies/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/fixup_drift_strategies/design_token_drift.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/fixup_drift_strategies/lexicon_violation.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/fixup_drift_strategies/url_drift.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/generator.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/graph.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/hitl_session.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/hooks/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/hooks/pre-commit +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/hooks/recipes/claude_settings_example.json +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/hooks/recipes/codex_hook.sh +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/hooks/recipes/git_post_commit.sh +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/hooks/recipes/git_pre_commit.sh +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/implementer/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/implementer/chunked_runner.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/implementer/typecheck_loop.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/implementer.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/inheritance.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/init/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/init/lexicon_suggest.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/init/stack_detector.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/knowledge_fetcher.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/lexicon_cli/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/lexicon_cli/formatters/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/lexicon_cli/formatters/html.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/lexicon_cli/formatters/json_fmt.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/lexicon_cli/formatters/md.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/lexicon_cli/inspector.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/lexicon_cli/manager.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/lexicon_cli/reporter.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/lexicon_cli/threshold.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/approval.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/best_practice_augmenter.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/criteria_expander.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/design_doc_extractor.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/impl_step_deriver.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/means_catalog_loader.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/parser.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/plan_deriver.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/prompt_builder.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/strategy_validator.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/templates/best_practice_augment_meta.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/templates/criteria_expand_meta.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/templates/design_doc_extract_meta.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/templates/impl_step_derive_meta.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/templates/implementation_step_catalog.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/templates/meta_instruction.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/templates/plan_derive_meta.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/llm/templates/verification_means_catalog.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/mcp_server.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/measure.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/parsing.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/planner.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/policy.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/preflight/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/preflight/defaults/cli.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/preflight/defaults/iot.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/preflight/defaults/mobile.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/preflight/defaults/web.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/propagate.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/propagator.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/registry.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/approval_repair.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/engine.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/git_patcher.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/history.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/llm_repair_engine.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/loop.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/primary_picker.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/proof_breaks.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/repair_result.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/repairability_classifier.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/schema.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/templates/analyze_meta.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/templates/propose_meta.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/templates/repair_strategy_meta.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/templates/repairability_meta.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair/verify_runner.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/repair_slice.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/require.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/require_plugins.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/require_propagate.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/required_artifacts/defaults/cli.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/required_artifacts/defaults/iot.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/required_artifacts/defaults/mobile.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/required_artifacts/defaults/web.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/required_artifacts_deriver.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/requirement_completeness/defaults/cli.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/requirement_completeness/defaults/iot.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/requirement_completeness/defaults/mobile.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/requirement_completeness/defaults/web.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/requirement_completeness_auditor.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/restore.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/routes_extractor.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/scanner.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/schema_refs.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/screen_flow_validator.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/screen_transition_extractor.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/screen_transitions/defaults.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/synth.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/templates/codd.yaml.tmpl +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/templates/conventions.yaml.tmpl +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/templates/data_dependencies.yaml.tmpl +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/templates/doc_links.yaml.tmpl +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/templates/extract_ai_prompt_baseline.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/templates/extracted/api-contract.md.j2 +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/templates/extracted/architecture-overview.md.j2 +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/templates/extracted/module-detail.md.j2 +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/templates/extracted/system-context.md.j2 +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/templates/gitignore.tmpl +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/templates/lexicon_questions.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/templates/overrides.yaml.tmpl +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/traceability.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/validator.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/watch/__init__.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/watch/events.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/watch/propagation_log.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/watch/propagation_pipeline.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/watch/test_runner.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/watch/watcher.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd/wiring.py +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ai_governance_eu_act/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ai_governance_eu_act/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ai_governance_eu_act/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ai_governance_eu_act/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ai_governance_eu_act/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ai_governance_eu_act/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/api_rest_openapi/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/api_rest_openapi/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/api_rest_openapi/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/api_rest_openapi/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/api_rest_openapi/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/api_rest_openapi/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/babok/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/babok/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/babok/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_event_cloudevents/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_event_cloudevents/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_event_cloudevents/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_event_cloudevents/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_event_cloudevents/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_event_cloudevents/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_graphql/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_graphql/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_graphql/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_graphql/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_graphql/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_graphql/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_grpc_proto/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_grpc_proto/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_grpc_proto/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_grpc_proto/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_grpc_proto/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/backend_grpc_proto/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_hipaa/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_hipaa/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_hipaa/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_hipaa/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_hipaa/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_hipaa/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_iso27001/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_iso27001/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_iso27001/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_iso27001/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_iso27001/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_iso27001/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_pci_dss_4/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_pci_dss_4/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_pci_dss_4/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_pci_dss_4/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_pci_dss_4/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/compliance_pci_dss_4/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_governance_appi_gdpr/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_governance_appi_gdpr/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_governance_appi_gdpr/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_governance_appi_gdpr/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_governance_appi_gdpr/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_governance_appi_gdpr/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_nosql_jsonschema/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_nosql_jsonschema/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_nosql_jsonschema/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_nosql_jsonschema/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_nosql_jsonschema/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_nosql_jsonschema/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_relational_iso_sql/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_relational_iso_sql/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_relational_iso_sql/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_relational_iso_sql/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_relational_iso_sql/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/data_relational_iso_sql/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_a11y_native/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_a11y_native/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_a11y_native/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_a11y_native/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_a11y_native/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_a11y_native/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_android_material3/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_android_material3/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_android_material3/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_android_material3/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_android_material3/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_android_material3/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_ios_hig/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_ios_hig/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_ios_hig/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_ios_hig/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_ios_hig/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/mobile_ios_hig/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_cicd_pipeline/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_cicd_pipeline/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_cicd_pipeline/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_cicd_pipeline/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_cicd_pipeline/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_cicd_pipeline/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_iac_terraform/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_iac_terraform/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_iac_terraform/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_iac_terraform/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_iac_terraform/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_iac_terraform/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_kubernetes/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_kubernetes/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_kubernetes/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_kubernetes/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_kubernetes/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_kubernetes/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_observability_otel/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_observability_otel/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_observability_otel/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_observability_otel/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_observability_otel/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/ops_observability_otel/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/process_iso25010/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/process_iso25010/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/process_iso25010/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/process_iso25010/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/process_iso25010/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/process_iso25010/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/process_test_iso29119/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/process_test_iso29119/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/process_test_iso29119/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/process_test_iso29119/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/process_test_iso29119/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/process_test_iso29119/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_authn_webauthn/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_authn_webauthn/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_authn_webauthn/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_authn_webauthn/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_authn_webauthn/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_authn_webauthn/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_browser_compat/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_browser_compat/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_browser_compat/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_browser_compat/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_browser_compat/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_browser_compat/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_forms_html5/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_forms_html5/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_forms_html5/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_forms_html5/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_forms_html5/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_forms_html5/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_performance_core_web_vitals/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_performance_core_web_vitals/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_performance_core_web_vitals/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_performance_core_web_vitals/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_performance_core_web_vitals/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_performance_core_web_vitals/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_pwa_manifest/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_pwa_manifest/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_pwa_manifest/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_pwa_manifest/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_pwa_manifest/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_pwa_manifest/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_responsive/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_responsive/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_responsive/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_responsive/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_responsive/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_responsive/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_security_owasp/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_security_owasp/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_security_owasp/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_security_owasp/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_security_owasp/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_security_owasp/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_seo_schemaorg/coverage_matrix.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_seo_schemaorg/elicit_extend.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_seo_schemaorg/lexicon.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_seo_schemaorg/manifest.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_seo_schemaorg/recommended_kinds.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/lexicons/web_seo_schemaorg/severity_rules.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/codd_plugins/stack_map.yaml +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/docs/cookbook/cdp_browser/README.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.0}/docs/requirements/README.md +0 -0
- {codd_dev-2.1.0 → codd_dev-2.3.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.3.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
|
|
@@ -610,6 +610,29 @@ def _add_deployment_graph(
|
|
|
610
610
|
)
|
|
611
611
|
verification_tests = extract_verification_tests(project_root, project_config, design_docs)
|
|
612
612
|
|
|
613
|
+
from codd.deployment.extractor import discover_deployment_impl_candidates
|
|
614
|
+
|
|
615
|
+
capability_patterns = _capability_patterns(project_config)
|
|
616
|
+
for impl_path in discover_deployment_impl_candidates(project_root, deployment_docs):
|
|
617
|
+
rel_id = impl_path.relative_to(project_root).as_posix()
|
|
618
|
+
if rel_id in dag.nodes:
|
|
619
|
+
continue
|
|
620
|
+
_add_node_once(
|
|
621
|
+
dag,
|
|
622
|
+
Node(
|
|
623
|
+
id=rel_id,
|
|
624
|
+
kind="impl_file",
|
|
625
|
+
path=rel_id,
|
|
626
|
+
attributes={
|
|
627
|
+
"language": _language_for_path(impl_path),
|
|
628
|
+
"imports": [],
|
|
629
|
+
"runtime_evidence": _runtime_evidence_for_file(impl_path, rel_id, capability_patterns),
|
|
630
|
+
"auto_registered_for_deployment": True,
|
|
631
|
+
},
|
|
632
|
+
),
|
|
633
|
+
)
|
|
634
|
+
impl_nodes[rel_id] = impl_path.resolve()
|
|
635
|
+
|
|
613
636
|
for deployment_doc in deployment_docs:
|
|
614
637
|
_add_node_once(
|
|
615
638
|
dag,
|
|
@@ -31,6 +31,17 @@ SMOKE_TEST_PATTERNS = ("tests/smoke/*.test.ts", "tests/smoke/*.spec.ts", "tests/
|
|
|
31
31
|
E2E_TEST_PATTERNS = ("tests/e2e/*.spec.ts", "tests/e2e/*.test.ts")
|
|
32
32
|
RUNTIME_CAPABILITY_INFERENCE_DEFAULTS = Path(__file__).parent / "defaults" / "runtime_capability_inference.yaml"
|
|
33
33
|
|
|
34
|
+
DEPLOYMENT_SECTION_IMPL_PATTERNS: dict[str, tuple[str, ...]] = {
|
|
35
|
+
"migrate": ("prisma/migrations/**/*", "schema.prisma", "**/migrations/**/*.sql"),
|
|
36
|
+
"seed": ("prisma/seed.ts", "prisma/seed.js", "scripts/seed.ts", "scripts/seed.js"),
|
|
37
|
+
"build": ("Dockerfile", "Containerfile", "package.json"),
|
|
38
|
+
"start": (
|
|
39
|
+
"main.ts", "main.js", "server.ts", "server.js",
|
|
40
|
+
"app.ts", "app.js", "index.ts", "index.js",
|
|
41
|
+
"src/main.ts", "src/main.js", "src/server.ts", "src/server.js",
|
|
42
|
+
),
|
|
43
|
+
}
|
|
44
|
+
|
|
34
45
|
|
|
35
46
|
def extract_deployment_nodes(project_root: Path, codd_config: dict[str, Any] | None = None) -> dict[str, list]:
|
|
36
47
|
"""Extract deployment document, runtime state, and verification test nodes."""
|
|
@@ -181,6 +192,37 @@ def extract_verification_tests(
|
|
|
181
192
|
return [tests[key] for key in sorted(tests)]
|
|
182
193
|
|
|
183
194
|
|
|
195
|
+
def discover_deployment_impl_candidates(
|
|
196
|
+
project_root: Path,
|
|
197
|
+
deployment_docs: list[DeploymentDocNode],
|
|
198
|
+
) -> list[Path]:
|
|
199
|
+
"""Return existing standard impl artifacts referenced by deployment doc sections.
|
|
200
|
+
|
|
201
|
+
Walks each deployment document's sections and matches keywords against
|
|
202
|
+
DEPLOYMENT_SECTION_IMPL_PATTERNS, then keeps the patterns that resolve to a
|
|
203
|
+
real file under ``project_root``. The mapping itself stays inside the
|
|
204
|
+
deployment plug-in so DAG core code can remain free of stack-specific
|
|
205
|
+
filenames; this helper just runs an existence check.
|
|
206
|
+
"""
|
|
207
|
+
|
|
208
|
+
root = Path(project_root)
|
|
209
|
+
seen: dict[str, Path] = {}
|
|
210
|
+
for doc in deployment_docs:
|
|
211
|
+
for section in doc.sections or []:
|
|
212
|
+
normalized = str(section).lower()
|
|
213
|
+
for keyword, patterns in DEPLOYMENT_SECTION_IMPL_PATTERNS.items():
|
|
214
|
+
if keyword not in normalized:
|
|
215
|
+
continue
|
|
216
|
+
for pattern in patterns:
|
|
217
|
+
for path in root.glob(pattern):
|
|
218
|
+
if not path.is_file():
|
|
219
|
+
continue
|
|
220
|
+
rel = path.relative_to(root).as_posix()
|
|
221
|
+
if rel not in seen:
|
|
222
|
+
seen[rel] = path
|
|
223
|
+
return list(seen.values())
|
|
224
|
+
|
|
225
|
+
|
|
184
226
|
def infer_deployment_edges(
|
|
185
227
|
project_root: Path,
|
|
186
228
|
deployment_docs: list[DeploymentDocNode],
|
|
@@ -35,6 +35,7 @@ class ElicitApplyEngine:
|
|
|
35
35
|
pending_path = self.elicit_dir / "pending_findings.yaml"
|
|
36
36
|
history_path = self.elicit_dir / "elicit_history.yaml"
|
|
37
37
|
findings_md_path = self.project_root / "findings.md"
|
|
38
|
+
requirements_path = _requirements_path(self.project_root)
|
|
38
39
|
|
|
39
40
|
ignored_doc = _read_yaml_mapping(ignored_path, default_key="ignored")
|
|
40
41
|
pending_doc = _read_yaml_mapping(pending_path, default_key="pending")
|
|
@@ -44,8 +45,12 @@ class ElicitApplyEngine:
|
|
|
44
45
|
pending_entries = _list_value(pending_doc, "pending")
|
|
45
46
|
history_entries = _list_value(history_doc, "sessions")
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
ignored_ids = _existing_finding_ids(ignored_entries)
|
|
49
|
+
pending_ids = _existing_finding_ids(pending_entries)
|
|
50
|
+
requirements_ids = _existing_ids_in_file(requirements_path)
|
|
51
|
+
accepted_for_requirements: list[Finding] = []
|
|
52
|
+
accepted_for_review: list[Finding] = []
|
|
53
|
+
pending_review: list[Finding] = []
|
|
49
54
|
rejected: list[Finding] = []
|
|
50
55
|
deferred: list[Finding] = []
|
|
51
56
|
duplicates: list[Finding] = []
|
|
@@ -53,31 +58,60 @@ class ElicitApplyEngine:
|
|
|
53
58
|
for finding in approved:
|
|
54
59
|
decision = _finding_decision(finding)
|
|
55
60
|
if decision == "reject":
|
|
61
|
+
_remove_finding_entry(pending_entries, finding.id)
|
|
62
|
+
pending_ids.discard(finding.id)
|
|
63
|
+
if finding.id in ignored_ids:
|
|
64
|
+
duplicates.append(finding)
|
|
65
|
+
continue
|
|
56
66
|
rejected.append(finding)
|
|
67
|
+
ignored_ids.add(finding.id)
|
|
57
68
|
continue
|
|
58
69
|
if decision == "defer":
|
|
59
70
|
deferred.append(finding)
|
|
60
71
|
continue
|
|
61
|
-
if
|
|
72
|
+
if decision == "pending":
|
|
73
|
+
if finding.id in ignored_ids or finding.id in requirements_ids:
|
|
74
|
+
duplicates.append(finding)
|
|
75
|
+
continue
|
|
76
|
+
if finding.id in pending_ids:
|
|
77
|
+
duplicates.append(finding)
|
|
78
|
+
continue
|
|
79
|
+
pending_review.append(finding)
|
|
80
|
+
pending_ids.add(finding.id)
|
|
81
|
+
continue
|
|
82
|
+
if _writes_requirements(finding):
|
|
83
|
+
if finding.id in ignored_ids or finding.id in requirements_ids:
|
|
84
|
+
duplicates.append(finding)
|
|
85
|
+
continue
|
|
86
|
+
_remove_finding_entry(pending_entries, finding.id)
|
|
87
|
+
pending_ids.discard(finding.id)
|
|
88
|
+
accepted_for_requirements.append(finding)
|
|
89
|
+
requirements_ids.add(finding.id)
|
|
90
|
+
continue
|
|
91
|
+
if finding.id in ignored_ids or finding.id in pending_ids or finding.id in requirements_ids:
|
|
62
92
|
duplicates.append(finding)
|
|
63
93
|
continue
|
|
64
|
-
|
|
65
|
-
|
|
94
|
+
accepted_for_review.append(finding)
|
|
95
|
+
pending_ids.add(finding.id)
|
|
66
96
|
|
|
67
97
|
for finding in rejected:
|
|
68
98
|
ignored_entries.append(_ignored_entry(finding, timestamp))
|
|
69
|
-
for finding in
|
|
99
|
+
for finding in [*accepted_for_review, *pending_review]:
|
|
70
100
|
pending_entries.append(_pending_entry(finding, timestamp))
|
|
71
101
|
|
|
72
102
|
history_entries.append(
|
|
73
103
|
{
|
|
74
104
|
"timestamp": timestamp,
|
|
75
105
|
"findings_total": len(approved),
|
|
76
|
-
"approved": len(
|
|
106
|
+
"approved": len(accepted_for_requirements) + len(accepted_for_review),
|
|
77
107
|
"rejected": len(rejected),
|
|
78
108
|
"deferred": len(deferred),
|
|
109
|
+
"pending": len(pending_review),
|
|
79
110
|
"duplicates": len(duplicates),
|
|
80
|
-
"findings_md": "findings.md" if
|
|
111
|
+
"findings_md": "findings.md" if accepted_for_review else None,
|
|
112
|
+
"requirements_md": _relative_path(requirements_path, self.project_root)
|
|
113
|
+
if accepted_for_requirements
|
|
114
|
+
else None,
|
|
81
115
|
}
|
|
82
116
|
)
|
|
83
117
|
|
|
@@ -89,12 +123,16 @@ class ElicitApplyEngine:
|
|
|
89
123
|
_write_yaml(history_path, {"sessions": history_entries})
|
|
90
124
|
files_updated.append(_relative_path(history_path, self.project_root))
|
|
91
125
|
|
|
92
|
-
if
|
|
93
|
-
|
|
126
|
+
if accepted_for_requirements:
|
|
127
|
+
_append_requirements(requirements_path, accepted_for_requirements)
|
|
128
|
+
files_updated.append(_relative_path(requirements_path, self.project_root))
|
|
129
|
+
|
|
130
|
+
if accepted_for_review:
|
|
131
|
+
findings_md_path.write_text(MdFormatter().format(accepted_for_review), encoding="utf-8")
|
|
94
132
|
files_updated.append(_relative_path(findings_md_path, self.project_root))
|
|
95
133
|
|
|
96
134
|
return ApplyResult(
|
|
97
|
-
applied_count=len(
|
|
135
|
+
applied_count=len(accepted_for_requirements) + len(accepted_for_review) + len(pending_review),
|
|
98
136
|
skipped_count=len(rejected) + len(deferred) + len(duplicates),
|
|
99
137
|
files_updated=files_updated,
|
|
100
138
|
)
|
|
@@ -128,17 +166,22 @@ def _findings_from_json(raw: str) -> list[Finding]:
|
|
|
128
166
|
|
|
129
167
|
|
|
130
168
|
_FINDING_COMMENT_RE = re.compile(r"<!--\s*codd:finding\s*(.*?)\s*-->", re.DOTALL)
|
|
169
|
+
_APPROVAL_LINE_RE = re.compile(
|
|
170
|
+
r"(?m)^-\s+approval:\s*\[([^\]]*)\]\s*`?([A-Za-z0-9][A-Za-z0-9_.:-]*)`?"
|
|
171
|
+
)
|
|
131
172
|
|
|
132
173
|
|
|
133
174
|
def _findings_from_markdown(raw: str) -> list[Finding]:
|
|
134
175
|
findings = [Finding.from_dict(json.loads(match.group(1))) for match in _FINDING_COMMENT_RE.finditer(raw)]
|
|
135
176
|
if findings:
|
|
136
|
-
|
|
177
|
+
approval_states = _approval_states_from_markdown(raw)
|
|
178
|
+
return [_with_approval_state(finding, approval_states.get(finding.id)) for finding in findings]
|
|
137
179
|
return _findings_from_markdown_fields(raw)
|
|
138
180
|
|
|
139
181
|
|
|
140
182
|
def _findings_from_markdown_fields(raw: str) -> list[Finding]:
|
|
141
183
|
findings: list[Finding] = []
|
|
184
|
+
approval_states = _approval_states_from_markdown(raw)
|
|
142
185
|
for section in re.split(r"(?m)^##\s+", raw)[1:]:
|
|
143
186
|
fields: dict[str, Any] = {}
|
|
144
187
|
for key in ("id", "kind", "severity", "name", "question", "rationale"):
|
|
@@ -148,10 +191,36 @@ def _findings_from_markdown_fields(raw: str) -> list[Finding]:
|
|
|
148
191
|
if value != "N/A":
|
|
149
192
|
fields[key] = value
|
|
150
193
|
if fields:
|
|
151
|
-
|
|
194
|
+
finding = Finding.from_dict(fields)
|
|
195
|
+
findings.append(_with_approval_state(finding, approval_states.get(finding.id)))
|
|
152
196
|
return findings
|
|
153
197
|
|
|
154
198
|
|
|
199
|
+
def _approval_states_from_markdown(raw: str) -> dict[str, str]:
|
|
200
|
+
states: dict[str, str] = {}
|
|
201
|
+
for match in _APPROVAL_LINE_RE.finditer(raw):
|
|
202
|
+
state = match.group(1).strip().lower()
|
|
203
|
+
finding_id = match.group(2).strip().strip("`")
|
|
204
|
+
if state:
|
|
205
|
+
states[finding_id] = state
|
|
206
|
+
return states
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _with_approval_state(finding: Finding, state: str | None) -> Finding:
|
|
210
|
+
if state is None:
|
|
211
|
+
return finding
|
|
212
|
+
details = dict(finding.details)
|
|
213
|
+
if state in {"x", "y", "yes", "approve", "approved"}:
|
|
214
|
+
details["approval"] = "approved"
|
|
215
|
+
elif state in {"r", "n", "no", "reject", "rejected"}:
|
|
216
|
+
details["approval"] = "rejected"
|
|
217
|
+
else:
|
|
218
|
+
details["approval"] = f"unknown:{state}"
|
|
219
|
+
payload = finding.to_dict()
|
|
220
|
+
payload["details"] = details
|
|
221
|
+
return Finding.from_dict(payload)
|
|
222
|
+
|
|
223
|
+
|
|
155
224
|
def _utc_timestamp() -> str:
|
|
156
225
|
return datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
|
157
226
|
|
|
@@ -197,16 +266,93 @@ def _existing_finding_ids(entries: list[Any]) -> set[str]:
|
|
|
197
266
|
return ids
|
|
198
267
|
|
|
199
268
|
|
|
269
|
+
def _remove_finding_entry(entries: list[Any], finding_id: str) -> None:
|
|
270
|
+
entries[:] = [
|
|
271
|
+
entry
|
|
272
|
+
for entry in entries
|
|
273
|
+
if _entry_finding_id(entry) != finding_id
|
|
274
|
+
]
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def _entry_finding_id(entry: Any) -> str | None:
|
|
278
|
+
if not isinstance(entry, dict):
|
|
279
|
+
return None
|
|
280
|
+
if "id" in entry:
|
|
281
|
+
return str(entry["id"])
|
|
282
|
+
finding = entry.get("finding")
|
|
283
|
+
if isinstance(finding, dict) and "id" in finding:
|
|
284
|
+
return str(finding["id"])
|
|
285
|
+
return None
|
|
286
|
+
|
|
287
|
+
|
|
200
288
|
def _finding_decision(finding: Finding) -> str:
|
|
201
289
|
raw = finding.details.get("decision", finding.details.get("approval", "approve"))
|
|
202
290
|
value = str(raw).strip().lower()
|
|
203
|
-
if value
|
|
291
|
+
if value.startswith("unknown:"):
|
|
292
|
+
return "pending"
|
|
293
|
+
if value in {"reject", "rejected", "no", "n", "r"}:
|
|
204
294
|
return "reject"
|
|
205
|
-
if value in {"
|
|
295
|
+
if value in {"pending", "unchecked", "unreviewed"}:
|
|
296
|
+
return "pending"
|
|
297
|
+
if value in {"defer", "deferred", "later", "d"}:
|
|
206
298
|
return "defer"
|
|
207
299
|
return "approve"
|
|
208
300
|
|
|
209
301
|
|
|
302
|
+
def _writes_requirements(finding: Finding) -> bool:
|
|
303
|
+
raw = finding.details.get("decision", finding.details.get("approval"))
|
|
304
|
+
if raw is None:
|
|
305
|
+
return False
|
|
306
|
+
return str(raw).strip().lower() in {"approve", "approved", "yes", "y", "x"}
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def _requirements_path(project_root: Path) -> Path:
|
|
310
|
+
candidates = [
|
|
311
|
+
project_root / "requirements.md",
|
|
312
|
+
project_root / "docs" / "requirements" / "requirements.md",
|
|
313
|
+
project_root / "docs" / "requirements.md",
|
|
314
|
+
project_root / ".codd" / "requirements.md",
|
|
315
|
+
]
|
|
316
|
+
for candidate in candidates:
|
|
317
|
+
if candidate.exists():
|
|
318
|
+
return candidate
|
|
319
|
+
return candidates[0]
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def _existing_ids_in_file(path: Path) -> set[str]:
|
|
323
|
+
if not path.exists():
|
|
324
|
+
return set()
|
|
325
|
+
text = path.read_text(encoding="utf-8", errors="replace")
|
|
326
|
+
return set(re.findall(r"\[([A-Za-z0-9][A-Za-z0-9_.:-]*)\]", text))
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def _append_requirements(path: Path, findings: list[Finding]) -> None:
|
|
330
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
331
|
+
existing = path.read_text(encoding="utf-8") if path.exists() else ""
|
|
332
|
+
entries = "\n\n".join(_requirements_entry(finding) for finding in findings)
|
|
333
|
+
parts = [existing.rstrip()]
|
|
334
|
+
heading = "## TODO (codd elicit approved findings)"
|
|
335
|
+
if heading not in existing:
|
|
336
|
+
parts.extend(["", heading])
|
|
337
|
+
parts.extend(["", entries])
|
|
338
|
+
path.write_text("\n".join(part for part in parts if part != "").rstrip() + "\n", encoding="utf-8")
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def _requirements_entry(finding: Finding) -> str:
|
|
342
|
+
lines = [f"- [ ] TODO [{finding.id}] {_summary(finding)}"]
|
|
343
|
+
if finding.question:
|
|
344
|
+
lines.append(f" - Question: {finding.question}")
|
|
345
|
+
if finding.rationale:
|
|
346
|
+
lines.append(f" - Rationale: {finding.rationale}")
|
|
347
|
+
if finding.related_requirement_ids:
|
|
348
|
+
lines.append(f" - Related requirements: {', '.join(finding.related_requirement_ids)}")
|
|
349
|
+
return "\n".join(lines)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def _summary(finding: Finding) -> str:
|
|
353
|
+
return finding.name or finding.question or finding.rationale or finding.id
|
|
354
|
+
|
|
355
|
+
|
|
210
356
|
def _ignored_entry(finding: Finding, timestamp: str) -> dict[str, Any]:
|
|
211
357
|
return {
|
|
212
358
|
"id": finding.id,
|
|
@@ -35,9 +35,16 @@ class ElicitEngine:
|
|
|
35
35
|
|
|
36
36
|
def run(self, project_root: Path, lexicon_config: Any | None = None) -> ElicitResult:
|
|
37
37
|
root = Path(project_root)
|
|
38
|
+
project_scope, project_phase = _project_scope_phase(root)
|
|
38
39
|
prompt = self.build_prompt(root, lexicon_config=lexicon_config)
|
|
39
40
|
raw_output = self.invoke(prompt, root)
|
|
40
41
|
result = self.deserialize_result(raw_output)
|
|
42
|
+
result.findings = _apply_scope_phase(
|
|
43
|
+
result.findings,
|
|
44
|
+
lexicon_config=lexicon_config,
|
|
45
|
+
scope=project_scope,
|
|
46
|
+
phase=project_phase,
|
|
47
|
+
)
|
|
41
48
|
result.findings = ElicitPersistence(root).filter_known(result.findings)
|
|
42
49
|
if not result.findings and result.lexicon_coverage_report:
|
|
43
50
|
non_gap = all(
|
|
@@ -173,6 +180,151 @@ def _existing_axes_text(project_root: Path) -> str:
|
|
|
173
180
|
return yaml.safe_dump(values, sort_keys=False, allow_unicode=True).strip()
|
|
174
181
|
|
|
175
182
|
|
|
183
|
+
def _project_scope_phase(project_root: Path) -> tuple[str, str]:
|
|
184
|
+
for name in ("project_lexicon.yaml", "project_lexicon.yml"):
|
|
185
|
+
path = project_root / name
|
|
186
|
+
if not path.is_file():
|
|
187
|
+
continue
|
|
188
|
+
payload = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
|
|
189
|
+
if not isinstance(payload, Mapping):
|
|
190
|
+
return "full", "production"
|
|
191
|
+
return (
|
|
192
|
+
str(payload.get("scope") or "full"),
|
|
193
|
+
str(payload.get("phase") or "production"),
|
|
194
|
+
)
|
|
195
|
+
return "full", "production"
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _apply_scope_phase(
|
|
199
|
+
findings: list[Finding],
|
|
200
|
+
*,
|
|
201
|
+
lexicon_config: Any | None,
|
|
202
|
+
scope: str,
|
|
203
|
+
phase: str,
|
|
204
|
+
) -> list[Finding]:
|
|
205
|
+
axis_concerns = _axis_concern_map(lexicon_config)
|
|
206
|
+
severity_rules = _mapping_attr(lexicon_config, "severity_rules")
|
|
207
|
+
filtered: list[Finding] = []
|
|
208
|
+
for finding in findings:
|
|
209
|
+
axis = _finding_axis(finding)
|
|
210
|
+
concern = axis_concerns.get(axis) if axis is not None else None
|
|
211
|
+
if not _scope_allows_concern(scope, concern):
|
|
212
|
+
continue
|
|
213
|
+
_apply_phase_severity(
|
|
214
|
+
finding,
|
|
215
|
+
axis=axis,
|
|
216
|
+
concern=concern,
|
|
217
|
+
phase=phase,
|
|
218
|
+
scope=scope,
|
|
219
|
+
severity_rules=severity_rules,
|
|
220
|
+
)
|
|
221
|
+
filtered.append(finding)
|
|
222
|
+
return filtered
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _axis_concern_map(lexicon_config: Any | None) -> dict[str, str]:
|
|
226
|
+
concerns: dict[str, str] = {}
|
|
227
|
+
for axis in _list_attr(lexicon_config, "coverage_axes"):
|
|
228
|
+
if not isinstance(axis, Mapping):
|
|
229
|
+
continue
|
|
230
|
+
axis_type = axis.get("axis_type")
|
|
231
|
+
concern = axis.get("concern")
|
|
232
|
+
if isinstance(axis_type, str) and isinstance(concern, str):
|
|
233
|
+
concerns[axis_type] = concern.strip().lower()
|
|
234
|
+
return concerns
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _finding_axis(finding: Finding) -> str | None:
|
|
238
|
+
for key in ("dimension", "axis", "axis_type"):
|
|
239
|
+
value = finding.details.get(key)
|
|
240
|
+
if isinstance(value, str) and value.strip():
|
|
241
|
+
return value.strip()
|
|
242
|
+
return None
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _scope_allows_concern(scope: str, concern: str | None) -> bool:
|
|
246
|
+
if concern is None:
|
|
247
|
+
return True
|
|
248
|
+
scope_value = scope.strip().lower()
|
|
249
|
+
concern_value = concern.strip().lower()
|
|
250
|
+
if scope_value == "system_implementation":
|
|
251
|
+
return concern_value in {"system", "both"}
|
|
252
|
+
if scope_value == "business_only":
|
|
253
|
+
return concern_value in {"business", "both"}
|
|
254
|
+
return True
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _apply_phase_severity(
|
|
258
|
+
finding: Finding,
|
|
259
|
+
*,
|
|
260
|
+
axis: str | None,
|
|
261
|
+
concern: str | None,
|
|
262
|
+
phase: str,
|
|
263
|
+
scope: str,
|
|
264
|
+
severity_rules: Mapping[str, Any],
|
|
265
|
+
) -> None:
|
|
266
|
+
phase_value = phase.strip().lower()
|
|
267
|
+
concern_value = (concern or "").strip().lower()
|
|
268
|
+
context = {
|
|
269
|
+
"axis": axis or "",
|
|
270
|
+
"dimension": axis or "",
|
|
271
|
+
"concern": concern_value,
|
|
272
|
+
"phase": phase_value,
|
|
273
|
+
"scope": scope.strip().lower(),
|
|
274
|
+
"severity": finding.severity,
|
|
275
|
+
}
|
|
276
|
+
if _apply_matching_severity_rule(finding, context, severity_rules):
|
|
277
|
+
return
|
|
278
|
+
if phase_value == "mvp" and concern_value == "business" and finding.severity != "info":
|
|
279
|
+
finding.severity = "info"
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def _apply_matching_severity_rule(
|
|
283
|
+
finding: Finding,
|
|
284
|
+
context: Mapping[str, str],
|
|
285
|
+
severity_rules: Mapping[str, Any],
|
|
286
|
+
) -> bool:
|
|
287
|
+
rules = severity_rules.get("rules", [])
|
|
288
|
+
if not isinstance(rules, list):
|
|
289
|
+
return False
|
|
290
|
+
for rule in rules:
|
|
291
|
+
if not isinstance(rule, Mapping):
|
|
292
|
+
continue
|
|
293
|
+
when = rule.get("when")
|
|
294
|
+
severity = rule.get("severity")
|
|
295
|
+
if not isinstance(when, str) or not isinstance(severity, str):
|
|
296
|
+
continue
|
|
297
|
+
if _condition_matches(when, context):
|
|
298
|
+
_set_severity(finding, severity)
|
|
299
|
+
return True
|
|
300
|
+
return False
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def _condition_matches(condition: str, context: Mapping[str, str]) -> bool:
|
|
304
|
+
parts = [
|
|
305
|
+
part.strip()
|
|
306
|
+
for part in re.split(r"\bAND\b", condition, flags=re.IGNORECASE)
|
|
307
|
+
if part.strip()
|
|
308
|
+
]
|
|
309
|
+
if not parts:
|
|
310
|
+
return False
|
|
311
|
+
for part in parts:
|
|
312
|
+
if "=" not in part:
|
|
313
|
+
return False
|
|
314
|
+
key_text, expected_text = part.split("=", 1)
|
|
315
|
+
key = key_text.strip().lower()
|
|
316
|
+
expected = expected_text.strip().lower()
|
|
317
|
+
if context.get(key, "").lower() != expected:
|
|
318
|
+
return False
|
|
319
|
+
return True
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def _set_severity(finding: Finding, severity: str) -> None:
|
|
323
|
+
cleaned = severity.strip().lower()
|
|
324
|
+
if cleaned in {"critical", "high", "medium", "info"}:
|
|
325
|
+
finding.severity = cleaned # type: ignore[assignment]
|
|
326
|
+
|
|
327
|
+
|
|
176
328
|
def _load_optional_codd_config(project_root: Path) -> dict[str, Any]:
|
|
177
329
|
for dirname in ("codd", ".codd"):
|
|
178
330
|
path = project_root / dirname / "codd.yaml"
|
|
@@ -237,6 +389,28 @@ def _string_attr(value: Any, name: str) -> str | None:
|
|
|
237
389
|
return None
|
|
238
390
|
|
|
239
391
|
|
|
392
|
+
def _mapping_attr(value: Any, name: str) -> Mapping[str, Any]:
|
|
393
|
+
candidate = getattr(value, name, None)
|
|
394
|
+
if isinstance(candidate, Mapping):
|
|
395
|
+
return candidate
|
|
396
|
+
if isinstance(value, Mapping):
|
|
397
|
+
candidate = value.get(name)
|
|
398
|
+
if isinstance(candidate, Mapping):
|
|
399
|
+
return candidate
|
|
400
|
+
return {}
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def _list_attr(value: Any, name: str) -> list[Any]:
|
|
404
|
+
candidate = getattr(value, name, None)
|
|
405
|
+
if isinstance(candidate, list):
|
|
406
|
+
return candidate
|
|
407
|
+
if isinstance(value, Mapping):
|
|
408
|
+
candidate = value.get(name)
|
|
409
|
+
if isinstance(candidate, list):
|
|
410
|
+
return candidate
|
|
411
|
+
return []
|
|
412
|
+
|
|
413
|
+
|
|
240
414
|
def _unique_paths(paths: list[Path]) -> list[Path]:
|
|
241
415
|
seen: set[Path] = set()
|
|
242
416
|
unique: list[Path] = []
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from dataclasses import dataclass
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
@@ -18,6 +18,8 @@ class LexiconConfig:
|
|
|
18
18
|
lexicon_name: str
|
|
19
19
|
prompt_extension_content: str
|
|
20
20
|
recommended_kinds: list[str]
|
|
21
|
+
coverage_axes: list[dict[str, Any]] = field(default_factory=list)
|
|
22
|
+
severity_rules: dict[str, Any] = field(default_factory=dict)
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
def load_lexicon(lexicon_path: Path) -> LexiconConfig:
|
|
@@ -54,10 +56,18 @@ def load_lexicon(lexicon_path: Path) -> LexiconConfig:
|
|
|
54
56
|
prompt_content = f"{base_prompt.rstrip()}\n\n{extension_body.lstrip()}"
|
|
55
57
|
|
|
56
58
|
recommended_kinds = _load_recommended_kinds(recommended_kinds_path)
|
|
59
|
+
coverage_axes = _load_coverage_axes(manifest_dir, manifest)
|
|
60
|
+
severity_rules = _load_optional_mapping_file(
|
|
61
|
+
manifest_dir,
|
|
62
|
+
_optional_str(manifest.get("severity_rules")) or "severity_rules.yaml",
|
|
63
|
+
"severity_rules",
|
|
64
|
+
)
|
|
57
65
|
return LexiconConfig(
|
|
58
66
|
lexicon_name=lexicon_name,
|
|
59
67
|
prompt_extension_content=prompt_content,
|
|
60
68
|
recommended_kinds=recommended_kinds,
|
|
69
|
+
coverage_axes=coverage_axes,
|
|
70
|
+
severity_rules=severity_rules,
|
|
61
71
|
)
|
|
62
72
|
|
|
63
73
|
|
|
@@ -154,3 +164,20 @@ def _load_recommended_kinds(path: Path) -> list[str]:
|
|
|
154
164
|
raise LexiconLoadError(f"recommended_kinds contains duplicate entry: {kind}")
|
|
155
165
|
kinds.append(kind)
|
|
156
166
|
return kinds
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _load_coverage_axes(base_dir: Path, manifest: dict[str, Any]) -> list[dict[str, Any]]:
|
|
170
|
+
lexicon_path_text = _optional_str(manifest.get("lexicon")) or "lexicon.yaml"
|
|
171
|
+
payload = _load_optional_mapping_file(base_dir, lexicon_path_text, "lexicon")
|
|
172
|
+
raw_axes = payload.get("coverage_axes", manifest.get("coverage_axes", []))
|
|
173
|
+
if not isinstance(raw_axes, list):
|
|
174
|
+
return []
|
|
175
|
+
return [dict(item) for item in raw_axes if isinstance(item, dict)]
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _load_optional_mapping_file(base_dir: Path, declared_path: str, label: str) -> dict[str, Any]:
|
|
179
|
+
try:
|
|
180
|
+
path = _resolve_existing_path(base_dir, declared_path, label)
|
|
181
|
+
except LexiconLoadError:
|
|
182
|
+
return {}
|
|
183
|
+
return _load_yaml_mapping(path, label)
|
|
@@ -13,6 +13,8 @@ import yaml
|
|
|
13
13
|
SCHEMA_PATH = Path(__file__).parent / "templates" / "lexicon_schema.yaml"
|
|
14
14
|
LEXICON_FILENAME = "project_lexicon.yaml"
|
|
15
15
|
REQUIRED_ARTIFACT_SOURCES = {"ai_derived", "user_override", "default_template"}
|
|
16
|
+
DEFAULT_SCOPE = "full"
|
|
17
|
+
DEFAULT_PHASE = "production"
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
@dataclass
|
|
@@ -92,6 +94,14 @@ class ProjectLexicon:
|
|
|
92
94
|
def required_artifacts(self) -> list[dict[str, Any]]:
|
|
93
95
|
return deepcopy(self._data.get("required_artifacts", []))
|
|
94
96
|
|
|
97
|
+
@property
|
|
98
|
+
def scope(self) -> str:
|
|
99
|
+
return str(self._data.get("scope") or DEFAULT_SCOPE)
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def phase(self) -> str:
|
|
103
|
+
return str(self._data.get("phase") or DEFAULT_PHASE)
|
|
104
|
+
|
|
95
105
|
def set_coverage_decisions(self, decisions: list[AskItem]) -> None:
|
|
96
106
|
self._data["coverage_decisions"] = [
|
|
97
107
|
ask_item_to_dict(item)
|
|
@@ -293,6 +303,10 @@ def validate_lexicon(data: dict[str, Any]) -> None:
|
|
|
293
303
|
if derived_from is not None and not isinstance(derived_from, list):
|
|
294
304
|
raise LexiconError(f"required_artifacts derived_from must be a list: {artifact}")
|
|
295
305
|
|
|
306
|
+
for field_name in ("scope", "phase"):
|
|
307
|
+
if field_name in data and not isinstance(data[field_name], str):
|
|
308
|
+
raise LexiconError(f"{field_name} must be a string")
|
|
309
|
+
|
|
296
310
|
|
|
297
311
|
def _load_schema() -> dict[str, Any]:
|
|
298
312
|
data = yaml.safe_load(SCHEMA_PATH.read_text(encoding="utf-8"))
|