codd-dev 2.0.0__tar.gz → 2.2.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.
Files changed (423) hide show
  1. {codd_dev-2.0.0 → codd_dev-2.2.0}/PKG-INFO +1 -1
  2. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/cli.py +124 -0
  3. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/elicit/apply.py +161 -15
  4. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/elicit/engine.py +174 -0
  5. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/elicit/lexicon_loader.py +28 -1
  6. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/lexicon.py +14 -0
  7. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/lexicon_cli/__init__.py +3 -0
  8. codd_dev-2.2.0/codd/lexicon_cli/threshold.py +159 -0
  9. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/templates/extracted/schema-design.md.j2 +1 -1
  10. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/templates/lexicon_schema.yaml +2 -0
  11. codd_dev-2.2.0/codd_plugins/lexicons/babok/lexicon.yaml +105 -0
  12. codd_dev-2.2.0/codd_plugins/lexicons/babok/severity_rules.yaml +53 -0
  13. {codd_dev-2.0.0 → codd_dev-2.2.0}/pyproject.toml +1 -1
  14. {codd_dev-2.0.0 → codd_dev-2.2.0}/.gitignore +0 -0
  15. {codd_dev-2.0.0 → codd_dev-2.2.0}/LICENSE +0 -0
  16. {codd_dev-2.0.0 → codd_dev-2.2.0}/README.md +0 -0
  17. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/__init__.py +0 -0
  18. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/__main__.py +0 -0
  19. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/_git_helper.py +0 -0
  20. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/ask_user_question_adapter.py +0 -0
  21. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/assembler.py +0 -0
  22. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/bridge.py +0 -0
  23. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/brownfield/__init__.py +0 -0
  24. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/brownfield/pipeline.py +0 -0
  25. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/clustering.py +0 -0
  26. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/coherence_adapters.py +0 -0
  27. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/coherence_engine.py +0 -0
  28. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/config.py +0 -0
  29. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/contracts.py +0 -0
  30. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/coverage_auditor.py +0 -0
  31. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/coverage_metrics.py +0 -0
  32. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/__init__.py +0 -0
  33. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/builder.py +0 -0
  34. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/checks/__init__.py +0 -0
  35. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/checks/depends_on_consistency.py +0 -0
  36. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/checks/deployment_completeness.py +0 -0
  37. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/checks/edge_validity.py +0 -0
  38. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/checks/environment_coverage.py +0 -0
  39. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/checks/implementation_coverage.py +0 -0
  40. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/checks/node_completeness.py +0 -0
  41. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/checks/task_completion.py +0 -0
  42. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/checks/transitive_closure.py +0 -0
  43. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/checks/user_journey_coherence.py +0 -0
  44. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/coverage_axes.py +0 -0
  45. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/defaults/cli.yaml +0 -0
  46. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/defaults/cpp_embedded.yaml +0 -0
  47. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/defaults/csharp.yaml +0 -0
  48. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/defaults/elixir.yaml +0 -0
  49. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/defaults/generic.yaml +0 -0
  50. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/defaults/iot.yaml +0 -0
  51. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/defaults/java.yaml +0 -0
  52. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/defaults/kotlin.yaml +0 -0
  53. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/defaults/mobile.yaml +0 -0
  54. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/defaults/ruby.yaml +0 -0
  55. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/defaults/rust.yaml +0 -0
  56. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/defaults/scala.yaml +0 -0
  57. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/defaults/swift.yaml +0 -0
  58. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/defaults/test_frameworks.yaml +0 -0
  59. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/defaults/web.yaml +0 -0
  60. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/extractor.py +0 -0
  61. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/dag/runner.py +0 -0
  62. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/defaults.yaml +0 -0
  63. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deploy_targets/__init__.py +0 -0
  64. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deploy_targets/app_service.py +0 -0
  65. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deploy_targets/base.py +0 -0
  66. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deploy_targets/docker_compose.py +0 -0
  67. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployer.py +0 -0
  68. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/__init__.py +0 -0
  69. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/checks/__init__.py +0 -0
  70. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/defaults/deploy_targets.yaml +0 -0
  71. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/defaults/runtime_capability_inference.yaml +0 -0
  72. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/defaults/schema_providers.yaml +0 -0
  73. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/defaults/verification_templates.yaml +0 -0
  74. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/extractor.py +0 -0
  75. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/__init__.py +0 -0
  76. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/ai_command.py +0 -0
  77. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/llm_consideration.py +0 -0
  78. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/schema/__init__.py +0 -0
  79. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/schema/prisma.py +0 -0
  80. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/target/__init__.py +0 -0
  81. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/target/docker_compose.py +0 -0
  82. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/verification/__init__.py +0 -0
  83. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/verification/assertion_handlers.py +0 -0
  84. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/verification/cdp_browser.py +0 -0
  85. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/verification/cdp_engines.py +0 -0
  86. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/verification/cdp_launchers.py +0 -0
  87. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/verification/cdp_wire.py +0 -0
  88. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/verification/curl.py +0 -0
  89. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/verification/form_strategies.py +0 -0
  90. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/verification/means_catalog.py +0 -0
  91. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/deployment/providers/verification/playwright.py +0 -0
  92. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/design_md.py +0 -0
  93. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/diff/__init__.py +0 -0
  94. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/diff/apply.py +0 -0
  95. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/diff/engine.py +0 -0
  96. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/diff/persistence.py +0 -0
  97. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/diff/templates/diff_prompt.md +0 -0
  98. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/drift.py +0 -0
  99. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/e2e_extractor.py +0 -0
  100. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/e2e_generator.py +0 -0
  101. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/e2e_runner.py +0 -0
  102. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/elicit/__init__.py +0 -0
  103. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/elicit/finding.py +0 -0
  104. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/elicit/formatters/__init__.py +0 -0
  105. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/elicit/formatters/base.py +0 -0
  106. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/elicit/formatters/interactive.py +0 -0
  107. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/elicit/formatters/json_fmt.py +0 -0
  108. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/elicit/formatters/md.py +0 -0
  109. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/elicit/persistence.py +0 -0
  110. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/elicit/templates/elicit_prompt_L0.md +0 -0
  111. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/env_refs.py +0 -0
  112. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/extract_ai.py +0 -0
  113. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/extractor.py +0 -0
  114. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/fixer.py +0 -0
  115. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/fixup_drift.py +0 -0
  116. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/fixup_drift_strategies/__init__.py +0 -0
  117. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/fixup_drift_strategies/design_token_drift.py +0 -0
  118. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/fixup_drift_strategies/lexicon_violation.py +0 -0
  119. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/fixup_drift_strategies/url_drift.py +0 -0
  120. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/generator.py +0 -0
  121. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/graph.py +0 -0
  122. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/hitl_session.py +0 -0
  123. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/hooks/__init__.py +0 -0
  124. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/hooks/pre-commit +0 -0
  125. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/hooks/recipes/claude_settings_example.json +0 -0
  126. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/hooks/recipes/codex_hook.sh +0 -0
  127. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/hooks/recipes/git_post_commit.sh +0 -0
  128. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/hooks/recipes/git_pre_commit.sh +0 -0
  129. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/implementer/__init__.py +0 -0
  130. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/implementer/chunked_runner.py +0 -0
  131. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/implementer/typecheck_loop.py +0 -0
  132. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/implementer.py +0 -0
  133. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/inheritance.py +0 -0
  134. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/init/__init__.py +0 -0
  135. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/init/lexicon_suggest.py +0 -0
  136. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/init/stack_detector.py +0 -0
  137. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/knowledge_fetcher.py +0 -0
  138. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/lexicon_cli/formatters/__init__.py +0 -0
  139. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/lexicon_cli/formatters/html.py +0 -0
  140. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/lexicon_cli/formatters/json_fmt.py +0 -0
  141. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/lexicon_cli/formatters/md.py +0 -0
  142. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/lexicon_cli/inspector.py +0 -0
  143. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/lexicon_cli/manager.py +0 -0
  144. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/lexicon_cli/reporter.py +0 -0
  145. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/__init__.py +0 -0
  146. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/approval.py +0 -0
  147. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/best_practice_augmenter.py +0 -0
  148. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/criteria_expander.py +0 -0
  149. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/design_doc_extractor.py +0 -0
  150. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/impl_step_deriver.py +0 -0
  151. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/means_catalog_loader.py +0 -0
  152. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/parser.py +0 -0
  153. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/plan_deriver.py +0 -0
  154. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/prompt_builder.py +0 -0
  155. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/strategy_validator.py +0 -0
  156. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/templates/best_practice_augment_meta.md +0 -0
  157. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/templates/criteria_expand_meta.md +0 -0
  158. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/templates/design_doc_extract_meta.md +0 -0
  159. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/templates/impl_step_derive_meta.md +0 -0
  160. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/templates/implementation_step_catalog.yaml +0 -0
  161. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/templates/meta_instruction.md +0 -0
  162. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/templates/plan_derive_meta.md +0 -0
  163. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/llm/templates/verification_means_catalog.yaml +0 -0
  164. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/mcp_server.py +0 -0
  165. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/measure.py +0 -0
  166. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/parsing.py +0 -0
  167. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/planner.py +0 -0
  168. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/policy.py +0 -0
  169. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/preflight/__init__.py +0 -0
  170. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/preflight/defaults/cli.yaml +0 -0
  171. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/preflight/defaults/iot.yaml +0 -0
  172. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/preflight/defaults/mobile.yaml +0 -0
  173. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/preflight/defaults/web.yaml +0 -0
  174. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/propagate.py +0 -0
  175. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/propagator.py +0 -0
  176. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/registry.py +0 -0
  177. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/__init__.py +0 -0
  178. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/approval_repair.py +0 -0
  179. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/engine.py +0 -0
  180. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/git_patcher.py +0 -0
  181. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/history.py +0 -0
  182. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/llm_repair_engine.py +0 -0
  183. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/loop.py +0 -0
  184. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/primary_picker.py +0 -0
  185. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/proof_breaks.py +0 -0
  186. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/repair_result.py +0 -0
  187. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/repairability_classifier.py +0 -0
  188. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/schema.py +0 -0
  189. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/templates/analyze_meta.md +0 -0
  190. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/templates/propose_meta.md +0 -0
  191. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/templates/repair_strategy_meta.md +0 -0
  192. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/templates/repairability_meta.md +0 -0
  193. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair/verify_runner.py +0 -0
  194. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/repair_slice.py +0 -0
  195. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/require.py +0 -0
  196. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/require_plugins.py +0 -0
  197. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/require_propagate.py +0 -0
  198. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/required_artifacts/defaults/cli.yaml +0 -0
  199. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/required_artifacts/defaults/iot.yaml +0 -0
  200. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/required_artifacts/defaults/mobile.yaml +0 -0
  201. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/required_artifacts/defaults/web.yaml +0 -0
  202. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/required_artifacts_deriver.py +0 -0
  203. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/requirement_completeness/defaults/cli.yaml +0 -0
  204. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/requirement_completeness/defaults/iot.yaml +0 -0
  205. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/requirement_completeness/defaults/mobile.yaml +0 -0
  206. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/requirement_completeness/defaults/web.yaml +0 -0
  207. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/requirement_completeness_auditor.py +0 -0
  208. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/restore.py +0 -0
  209. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/routes_extractor.py +0 -0
  210. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/scanner.py +0 -0
  211. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/schema_refs.py +0 -0
  212. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/screen_flow_validator.py +0 -0
  213. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/screen_transition_extractor.py +0 -0
  214. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/screen_transitions/defaults.yaml +0 -0
  215. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/synth.py +0 -0
  216. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/templates/codd.yaml.tmpl +0 -0
  217. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/templates/conventions.yaml.tmpl +0 -0
  218. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/templates/data_dependencies.yaml.tmpl +0 -0
  219. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/templates/doc_links.yaml.tmpl +0 -0
  220. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/templates/extract_ai_prompt_baseline.md +0 -0
  221. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/templates/extracted/api-contract.md.j2 +0 -0
  222. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/templates/extracted/architecture-overview.md.j2 +0 -0
  223. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/templates/extracted/module-detail.md.j2 +0 -0
  224. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/templates/extracted/system-context.md.j2 +0 -0
  225. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/templates/gitignore.tmpl +0 -0
  226. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/templates/lexicon_questions.md +0 -0
  227. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/templates/overrides.yaml.tmpl +0 -0
  228. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/traceability.py +0 -0
  229. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/validator.py +0 -0
  230. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/watch/__init__.py +0 -0
  231. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/watch/events.py +0 -0
  232. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/watch/propagation_log.py +0 -0
  233. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/watch/propagation_pipeline.py +0 -0
  234. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/watch/test_runner.py +0 -0
  235. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/watch/watcher.py +0 -0
  236. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd/wiring.py +0 -0
  237. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ai_governance_eu_act/coverage_matrix.md +0 -0
  238. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ai_governance_eu_act/elicit_extend.md +0 -0
  239. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ai_governance_eu_act/lexicon.yaml +0 -0
  240. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ai_governance_eu_act/manifest.yaml +0 -0
  241. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ai_governance_eu_act/recommended_kinds.yaml +0 -0
  242. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ai_governance_eu_act/severity_rules.yaml +0 -0
  243. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/api_rest_openapi/coverage_matrix.md +0 -0
  244. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/api_rest_openapi/elicit_extend.md +0 -0
  245. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/api_rest_openapi/lexicon.yaml +0 -0
  246. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/api_rest_openapi/manifest.yaml +0 -0
  247. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/api_rest_openapi/recommended_kinds.yaml +0 -0
  248. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/api_rest_openapi/severity_rules.yaml +0 -0
  249. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/babok/elicit_extend.md +0 -0
  250. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/babok/manifest.yaml +0 -0
  251. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/babok/recommended_kinds.yaml +0 -0
  252. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_event_cloudevents/coverage_matrix.md +0 -0
  253. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_event_cloudevents/elicit_extend.md +0 -0
  254. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_event_cloudevents/lexicon.yaml +0 -0
  255. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_event_cloudevents/manifest.yaml +0 -0
  256. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_event_cloudevents/recommended_kinds.yaml +0 -0
  257. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_event_cloudevents/severity_rules.yaml +0 -0
  258. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_graphql/coverage_matrix.md +0 -0
  259. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_graphql/elicit_extend.md +0 -0
  260. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_graphql/lexicon.yaml +0 -0
  261. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_graphql/manifest.yaml +0 -0
  262. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_graphql/recommended_kinds.yaml +0 -0
  263. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_graphql/severity_rules.yaml +0 -0
  264. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_grpc_proto/coverage_matrix.md +0 -0
  265. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_grpc_proto/elicit_extend.md +0 -0
  266. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_grpc_proto/lexicon.yaml +0 -0
  267. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_grpc_proto/manifest.yaml +0 -0
  268. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_grpc_proto/recommended_kinds.yaml +0 -0
  269. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/backend_grpc_proto/severity_rules.yaml +0 -0
  270. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_hipaa/coverage_matrix.md +0 -0
  271. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_hipaa/elicit_extend.md +0 -0
  272. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_hipaa/lexicon.yaml +0 -0
  273. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_hipaa/manifest.yaml +0 -0
  274. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_hipaa/recommended_kinds.yaml +0 -0
  275. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_hipaa/severity_rules.yaml +0 -0
  276. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_iso27001/coverage_matrix.md +0 -0
  277. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_iso27001/elicit_extend.md +0 -0
  278. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_iso27001/lexicon.yaml +0 -0
  279. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_iso27001/manifest.yaml +0 -0
  280. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_iso27001/recommended_kinds.yaml +0 -0
  281. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_iso27001/severity_rules.yaml +0 -0
  282. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_pci_dss_4/coverage_matrix.md +0 -0
  283. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_pci_dss_4/elicit_extend.md +0 -0
  284. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_pci_dss_4/lexicon.yaml +0 -0
  285. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_pci_dss_4/manifest.yaml +0 -0
  286. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_pci_dss_4/recommended_kinds.yaml +0 -0
  287. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/compliance_pci_dss_4/severity_rules.yaml +0 -0
  288. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/coverage_matrix.md +0 -0
  289. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/elicit_extend.md +0 -0
  290. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/lexicon.yaml +0 -0
  291. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/manifest.yaml +0 -0
  292. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/recommended_kinds.yaml +0 -0
  293. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_eventsourcing_es_cqrs/severity_rules.yaml +0 -0
  294. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_governance_appi_gdpr/coverage_matrix.md +0 -0
  295. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_governance_appi_gdpr/elicit_extend.md +0 -0
  296. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_governance_appi_gdpr/lexicon.yaml +0 -0
  297. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_governance_appi_gdpr/manifest.yaml +0 -0
  298. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_governance_appi_gdpr/recommended_kinds.yaml +0 -0
  299. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_governance_appi_gdpr/severity_rules.yaml +0 -0
  300. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_nosql_jsonschema/coverage_matrix.md +0 -0
  301. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_nosql_jsonschema/elicit_extend.md +0 -0
  302. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_nosql_jsonschema/lexicon.yaml +0 -0
  303. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_nosql_jsonschema/manifest.yaml +0 -0
  304. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_nosql_jsonschema/recommended_kinds.yaml +0 -0
  305. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_nosql_jsonschema/severity_rules.yaml +0 -0
  306. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_relational_iso_sql/coverage_matrix.md +0 -0
  307. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_relational_iso_sql/elicit_extend.md +0 -0
  308. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_relational_iso_sql/lexicon.yaml +0 -0
  309. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_relational_iso_sql/manifest.yaml +0 -0
  310. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_relational_iso_sql/recommended_kinds.yaml +0 -0
  311. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/data_relational_iso_sql/severity_rules.yaml +0 -0
  312. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_a11y_native/coverage_matrix.md +0 -0
  313. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_a11y_native/elicit_extend.md +0 -0
  314. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_a11y_native/lexicon.yaml +0 -0
  315. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_a11y_native/manifest.yaml +0 -0
  316. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_a11y_native/recommended_kinds.yaml +0 -0
  317. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_a11y_native/severity_rules.yaml +0 -0
  318. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_android_material3/coverage_matrix.md +0 -0
  319. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_android_material3/elicit_extend.md +0 -0
  320. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_android_material3/lexicon.yaml +0 -0
  321. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_android_material3/manifest.yaml +0 -0
  322. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_android_material3/recommended_kinds.yaml +0 -0
  323. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_android_material3/severity_rules.yaml +0 -0
  324. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_ios_hig/coverage_matrix.md +0 -0
  325. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_ios_hig/elicit_extend.md +0 -0
  326. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_ios_hig/lexicon.yaml +0 -0
  327. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_ios_hig/manifest.yaml +0 -0
  328. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_ios_hig/recommended_kinds.yaml +0 -0
  329. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/mobile_ios_hig/severity_rules.yaml +0 -0
  330. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_cicd_pipeline/coverage_matrix.md +0 -0
  331. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_cicd_pipeline/elicit_extend.md +0 -0
  332. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_cicd_pipeline/lexicon.yaml +0 -0
  333. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_cicd_pipeline/manifest.yaml +0 -0
  334. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_cicd_pipeline/recommended_kinds.yaml +0 -0
  335. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_cicd_pipeline/severity_rules.yaml +0 -0
  336. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_iac_terraform/coverage_matrix.md +0 -0
  337. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_iac_terraform/elicit_extend.md +0 -0
  338. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_iac_terraform/lexicon.yaml +0 -0
  339. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_iac_terraform/manifest.yaml +0 -0
  340. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_iac_terraform/recommended_kinds.yaml +0 -0
  341. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_iac_terraform/severity_rules.yaml +0 -0
  342. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_kubernetes/coverage_matrix.md +0 -0
  343. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_kubernetes/elicit_extend.md +0 -0
  344. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_kubernetes/lexicon.yaml +0 -0
  345. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_kubernetes/manifest.yaml +0 -0
  346. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_kubernetes/recommended_kinds.yaml +0 -0
  347. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_kubernetes/severity_rules.yaml +0 -0
  348. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_observability_otel/coverage_matrix.md +0 -0
  349. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_observability_otel/elicit_extend.md +0 -0
  350. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_observability_otel/lexicon.yaml +0 -0
  351. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_observability_otel/manifest.yaml +0 -0
  352. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_observability_otel/recommended_kinds.yaml +0 -0
  353. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/ops_observability_otel/severity_rules.yaml +0 -0
  354. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/process_iso25010/coverage_matrix.md +0 -0
  355. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/process_iso25010/elicit_extend.md +0 -0
  356. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/process_iso25010/lexicon.yaml +0 -0
  357. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/process_iso25010/manifest.yaml +0 -0
  358. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/process_iso25010/recommended_kinds.yaml +0 -0
  359. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/process_iso25010/severity_rules.yaml +0 -0
  360. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/process_test_iso29119/coverage_matrix.md +0 -0
  361. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/process_test_iso29119/elicit_extend.md +0 -0
  362. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/process_test_iso29119/lexicon.yaml +0 -0
  363. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/process_test_iso29119/manifest.yaml +0 -0
  364. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/process_test_iso29119/recommended_kinds.yaml +0 -0
  365. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/process_test_iso29119/severity_rules.yaml +0 -0
  366. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/coverage_matrix.md +0 -0
  367. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/elicit_extend.md +0 -0
  368. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/lexicon.yaml +0 -0
  369. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/manifest.yaml +0 -0
  370. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/recommended_kinds.yaml +0 -0
  371. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_a11y_wcag22_aa/severity_rules.yaml +0 -0
  372. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_authn_webauthn/coverage_matrix.md +0 -0
  373. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_authn_webauthn/elicit_extend.md +0 -0
  374. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_authn_webauthn/lexicon.yaml +0 -0
  375. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_authn_webauthn/manifest.yaml +0 -0
  376. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_authn_webauthn/recommended_kinds.yaml +0 -0
  377. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_authn_webauthn/severity_rules.yaml +0 -0
  378. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_browser_compat/coverage_matrix.md +0 -0
  379. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_browser_compat/elicit_extend.md +0 -0
  380. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_browser_compat/lexicon.yaml +0 -0
  381. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_browser_compat/manifest.yaml +0 -0
  382. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_browser_compat/recommended_kinds.yaml +0 -0
  383. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_browser_compat/severity_rules.yaml +0 -0
  384. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_forms_html5/coverage_matrix.md +0 -0
  385. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_forms_html5/elicit_extend.md +0 -0
  386. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_forms_html5/lexicon.yaml +0 -0
  387. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_forms_html5/manifest.yaml +0 -0
  388. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_forms_html5/recommended_kinds.yaml +0 -0
  389. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_forms_html5/severity_rules.yaml +0 -0
  390. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_performance_core_web_vitals/coverage_matrix.md +0 -0
  391. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_performance_core_web_vitals/elicit_extend.md +0 -0
  392. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_performance_core_web_vitals/lexicon.yaml +0 -0
  393. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_performance_core_web_vitals/manifest.yaml +0 -0
  394. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_performance_core_web_vitals/recommended_kinds.yaml +0 -0
  395. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_performance_core_web_vitals/severity_rules.yaml +0 -0
  396. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_pwa_manifest/coverage_matrix.md +0 -0
  397. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_pwa_manifest/elicit_extend.md +0 -0
  398. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_pwa_manifest/lexicon.yaml +0 -0
  399. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_pwa_manifest/manifest.yaml +0 -0
  400. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_pwa_manifest/recommended_kinds.yaml +0 -0
  401. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_pwa_manifest/severity_rules.yaml +0 -0
  402. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_responsive/coverage_matrix.md +0 -0
  403. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_responsive/elicit_extend.md +0 -0
  404. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_responsive/lexicon.yaml +0 -0
  405. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_responsive/manifest.yaml +0 -0
  406. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_responsive/recommended_kinds.yaml +0 -0
  407. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_responsive/severity_rules.yaml +0 -0
  408. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_security_owasp/coverage_matrix.md +0 -0
  409. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_security_owasp/elicit_extend.md +0 -0
  410. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_security_owasp/lexicon.yaml +0 -0
  411. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_security_owasp/manifest.yaml +0 -0
  412. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_security_owasp/recommended_kinds.yaml +0 -0
  413. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_security_owasp/severity_rules.yaml +0 -0
  414. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_seo_schemaorg/coverage_matrix.md +0 -0
  415. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_seo_schemaorg/elicit_extend.md +0 -0
  416. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_seo_schemaorg/lexicon.yaml +0 -0
  417. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_seo_schemaorg/manifest.yaml +0 -0
  418. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_seo_schemaorg/recommended_kinds.yaml +0 -0
  419. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/lexicons/web_seo_schemaorg/severity_rules.yaml +0 -0
  420. {codd_dev-2.0.0 → codd_dev-2.2.0}/codd_plugins/stack_map.yaml +0 -0
  421. {codd_dev-2.0.0 → codd_dev-2.2.0}/docs/cookbook/cdp_browser/README.md +0 -0
  422. {codd_dev-2.0.0 → codd_dev-2.2.0}/docs/requirements/README.md +0 -0
  423. {codd_dev-2.0.0 → codd_dev-2.2.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.0.0
3
+ Version: 2.2.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
@@ -2973,6 +2973,130 @@ def coverage_report_cmd(
2973
2973
  click.echo(f"Report: {_display_path(output_path, project_root)}")
2974
2974
 
2975
2975
 
2976
+ @coverage.command("check")
2977
+ @click.option(
2978
+ "--lexicons",
2979
+ default="all",
2980
+ show_default=True,
2981
+ help="Lexicons to include: all or a comma-separated id list.",
2982
+ )
2983
+ @click.option("--path", "project_path", default=".", show_default=True, help="Project root directory")
2984
+ @click.option(
2985
+ "--threshold",
2986
+ "global_threshold",
2987
+ type=float,
2988
+ default=None,
2989
+ help="Global covered_text_match_pct threshold override.",
2990
+ )
2991
+ @click.option(
2992
+ "--threshold-file",
2993
+ type=click.Path(exists=True, dir_okay=False, path_type=Path),
2994
+ default=None,
2995
+ help="External threshold YAML file.",
2996
+ )
2997
+ @click.option(
2998
+ "--format",
2999
+ "format_name",
3000
+ type=click.Choice(["human", "json", "md"]),
3001
+ default="human",
3002
+ show_default=True,
3003
+ help="Output format.",
3004
+ )
3005
+ @click.option("--with-ai", is_flag=True, default=False, help="Use AI-backed elicit coverage mode.")
3006
+ @click.option("--ai-cmd", default=None, help="Override AI CLI command for --with-ai.")
3007
+ @click.option("--exit-zero", is_flag=True, default=False, help="Always exit 0 for threshold violations.")
3008
+ def coverage_check_cmd(
3009
+ lexicons: str,
3010
+ project_path: str,
3011
+ global_threshold: float | None,
3012
+ threshold_file: Path | None,
3013
+ format_name: str,
3014
+ with_ai: bool,
3015
+ ai_cmd: str | None,
3016
+ exit_zero: bool,
3017
+ ) -> None:
3018
+ """Run a lexicon coverage threshold gate."""
3019
+ from dataclasses import asdict
3020
+
3021
+ from codd.lexicon_cli.formatters.json_fmt import to_json
3022
+ from codd.lexicon_cli.reporter import CoverageReporter
3023
+ from codd.lexicon_cli.threshold import ThresholdConfig, evaluate, load_thresholds
3024
+
3025
+ project_root = Path(project_path).resolve()
3026
+ try:
3027
+ report = CoverageReporter(project_root).build(lexicons, with_ai=with_ai, ai_command=ai_cmd)
3028
+ config = load_thresholds(threshold_file or _default_threshold_path(project_root))
3029
+ if global_threshold is not None:
3030
+ config = ThresholdConfig(default_pct=global_threshold)
3031
+ violations = evaluate(report, config)
3032
+ except (OSError, ValueError, json.JSONDecodeError, yaml.YAMLError) as exc:
3033
+ click.echo(f"Error: {exc}")
3034
+ raise SystemExit(2)
3035
+
3036
+ payload = {
3037
+ "status": "fail" if violations else "pass",
3038
+ "thresholds": asdict(config),
3039
+ "totals": report.totals,
3040
+ "violations": [asdict(violation) for violation in violations],
3041
+ }
3042
+ if format_name == "json":
3043
+ click.echo(to_json(payload), nl=False)
3044
+ elif format_name == "md":
3045
+ click.echo(_format_coverage_check_md(payload), nl=False)
3046
+ else:
3047
+ click.echo(_format_coverage_check_human(payload), nl=False)
3048
+
3049
+ raise SystemExit(0 if exit_zero or not violations else 1)
3050
+
3051
+
3052
+ def _default_threshold_path(project_root: Path) -> Path | None:
3053
+ codd_dir = find_codd_dir(project_root)
3054
+ return codd_dir / "codd.yaml" if codd_dir is not None else None
3055
+
3056
+
3057
+ def _format_coverage_check_human(payload: dict[str, Any]) -> str:
3058
+ status = str(payload["status"]).upper()
3059
+ totals = payload["totals"]
3060
+ lines = [
3061
+ f"Coverage check {status}",
3062
+ f"Axes: {totals['covered']}/{totals['axes']} covered ({totals['covered_pct']:.2f}%)",
3063
+ ]
3064
+ violations = payload["violations"]
3065
+ if violations:
3066
+ lines.append("Violations:")
3067
+ for violation in violations:
3068
+ axis = violation["axis"] or "<overall>"
3069
+ lines.append(
3070
+ f" - {violation['lexicon_id']} {axis}: "
3071
+ f"{violation['observed_pct']:.2f}% < {violation['required_pct']:.2f}%"
3072
+ )
3073
+ return "\n".join(lines) + "\n"
3074
+
3075
+
3076
+ def _format_coverage_check_md(payload: dict[str, Any]) -> str:
3077
+ totals = payload["totals"]
3078
+ lines = [
3079
+ "# Coverage Threshold Check",
3080
+ "",
3081
+ f"Status: **{str(payload['status']).upper()}**",
3082
+ f"Axes: {totals['covered']}/{totals['axes']} covered ({totals['covered_pct']:.2f}%)",
3083
+ "",
3084
+ "| Lexicon | Axis | Observed | Required |",
3085
+ "| --- | --- | ---: | ---: |",
3086
+ ]
3087
+ violations = payload["violations"]
3088
+ if violations:
3089
+ for violation in violations:
3090
+ axis = violation["axis"] or "<overall>"
3091
+ lines.append(
3092
+ f"| {violation['lexicon_id']} | {axis} | "
3093
+ f"{violation['observed_pct']:.2f}% | {violation['required_pct']:.2f}% |"
3094
+ )
3095
+ else:
3096
+ lines.append("| - | - | - | - |")
3097
+ return "\n".join(lines) + "\n"
3098
+
3099
+
2976
3100
  @main.command("deploy")
2977
3101
  @click.option("--target", default=None, help="Deploy target name from deploy.yaml")
2978
3102
  @click.option(
@@ -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
- existing_ids = _existing_finding_ids(ignored_entries) | _existing_finding_ids(pending_entries)
48
- accepted: list[Finding] = []
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 finding.id in existing_ids:
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
- accepted.append(finding)
65
- existing_ids.add(finding.id)
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 accepted:
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(accepted),
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 accepted else None,
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 accepted:
93
- findings_md_path.write_text(MdFormatter().format(accepted), encoding="utf-8")
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(accepted),
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
- return findings
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
- findings.append(Finding.from_dict(fields))
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 in {"reject", "rejected", "no", "n"}:
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 {"defer", "deferred", "later", "pending", "d"}:
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)