serenecode 0.4.0__tar.gz → 0.5.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 (172) hide show
  1. {serenecode-0.4.0 → serenecode-0.5.0}/CLAUDE.md +1 -1
  2. {serenecode-0.4.0 → serenecode-0.5.0}/PKG-INFO +25 -10
  3. {serenecode-0.4.0 → serenecode-0.5.0}/README.md +24 -9
  4. serenecode-0.5.0/SPEC.md +290 -0
  5. {serenecode-0.4.0 → serenecode-0.5.0}/docs/VERIFICATION_LEVELS.md +2 -2
  6. {serenecode-0.4.0 → serenecode-0.5.0}/pyproject.toml +1 -1
  7. serenecode-0.5.0/src/serenecode/adapters/coverage_adapter.py +718 -0
  8. serenecode-0.5.0/src/serenecode/adapters/coverage_suggestions.py +519 -0
  9. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/adapters/crosshair_adapter.py +65 -472
  10. serenecode-0.5.0/src/serenecode/adapters/hypothesis_adapter.py +841 -0
  11. serenecode-0.5.0/src/serenecode/adapters/hypothesis_strategies.py +965 -0
  12. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/adapters/local_fs.py +1 -0
  13. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/adapters/module_loader.py +2 -0
  14. serenecode-0.5.0/src/serenecode/checker/compositional.py +972 -0
  15. serenecode-0.5.0/src/serenecode/checker/compositional_integration.py +934 -0
  16. serenecode-0.5.0/src/serenecode/checker/compositional_parsing.py +729 -0
  17. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/checker/spec_traceability.py +278 -282
  18. serenecode-0.5.0/src/serenecode/checker/structural.py +1000 -0
  19. serenecode-0.5.0/src/serenecode/checker/structural_helpers.py +999 -0
  20. serenecode-0.5.0/src/serenecode/checker/structural_quality.py +997 -0
  21. serenecode-0.5.0/src/serenecode/checker/symbolic.py +165 -0
  22. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/cli.py +71 -447
  23. serenecode-0.5.0/src/serenecode/cli_helpers.py +471 -0
  24. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/config.py +159 -35
  25. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/contracts/predicates.py +3 -0
  26. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/core/exceptions.py +2 -0
  27. serenecode-0.5.0/src/serenecode/core/module_health.py +527 -0
  28. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/core/pipeline.py +315 -473
  29. serenecode-0.5.0/src/serenecode/core/pipeline_helpers.py +223 -0
  30. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/init.py +21 -35
  31. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/mcp/schemas.py +7 -5
  32. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/mcp/server.py +44 -12
  33. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/mcp/tools.py +131 -456
  34. serenecode-0.5.0/src/serenecode/mcp/tools_spec.py +458 -0
  35. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/models.py +16 -2
  36. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/ports/coverage_analyzer.py +2 -2
  37. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/ports/file_system.py +1 -0
  38. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/reporter.py +203 -172
  39. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/source_discovery.py +1 -0
  40. serenecode-0.5.0/src/serenecode/support/crosshair_parsing.py +435 -0
  41. serenecode-0.5.0/src/serenecode/support/hypothesis_refinement.py +240 -0
  42. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/templates/content.py +52 -0
  43. {serenecode-0.4.0 → serenecode-0.5.0}/tests/e2e/test_cli_branches.py +38 -1
  44. {serenecode-0.4.0 → serenecode-0.5.0}/tests/e2e/test_init_command.py +6 -5
  45. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_adapter_internals.py +16 -16
  46. serenecode-0.5.0/tests/integration/test_coverage_suggestions.py +24 -0
  47. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_crosshair_adapter_helpers.py +2 -0
  48. serenecode-0.5.0/tests/integration/test_crosshair_parsing.py +19 -0
  49. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_hypothesis_adapter_helpers.py +8 -6
  50. serenecode-0.5.0/tests/integration/test_hypothesis_refinement.py +16 -0
  51. serenecode-0.5.0/tests/integration/test_hypothesis_strategies.py +11 -0
  52. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_schemas.py +1 -0
  53. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_server.py +4 -1
  54. serenecode-0.5.0/tests/integration/test_tools_spec.py +11 -0
  55. serenecode-0.5.0/tests/unit/checker/test_compositional_integration.py +11 -0
  56. serenecode-0.5.0/tests/unit/checker/test_compositional_parsing.py +10 -0
  57. serenecode-0.5.0/tests/unit/checker/test_module_health.py +323 -0
  58. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/checker/test_structural.py +16 -12
  59. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/checker/test_structural_helpers.py +10 -6
  60. serenecode-0.5.0/tests/unit/checker/test_structural_quality.py +23 -0
  61. serenecode-0.5.0/tests/unit/contracts/__init__.py +0 -0
  62. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/contracts/test_predicates_hypothesis.py +1 -1
  63. serenecode-0.5.0/tests/unit/mcp/__init__.py +0 -0
  64. serenecode-0.5.0/tests/unit/mcp/test_tool_module_health.py +89 -0
  65. serenecode-0.5.0/tests/unit/test_cli_helpers.py +27 -0
  66. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/test_config.py +30 -0
  67. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/test_models.py +39 -0
  68. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/test_pipeline.py +11 -7
  69. serenecode-0.5.0/tests/unit/test_pipeline_helpers.py +20 -0
  70. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/test_reporter.py +2 -0
  71. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/test_templates_content.py +6 -0
  72. serenecode-0.4.0/AGENTS.md +0 -76
  73. serenecode-0.4.0/FEATURE_SPEC.md +0 -222
  74. serenecode-0.4.0/IMPLEMENTATION_PLAN.md +0 -395
  75. serenecode-0.4.0/SERENECODE.md +0 -719
  76. serenecode-0.4.0/src/serenecode/adapters/coverage_adapter.py +0 -1188
  77. serenecode-0.4.0/src/serenecode/adapters/hypothesis_adapter.py +0 -2023
  78. serenecode-0.4.0/src/serenecode/checker/compositional.py +0 -2559
  79. serenecode-0.4.0/src/serenecode/checker/structural.py +0 -2909
  80. serenecode-0.4.0/src/serenecode/checker/symbolic.py +0 -178
  81. {serenecode-0.4.0 → serenecode-0.5.0}/.gitignore +0 -0
  82. {serenecode-0.4.0 → serenecode-0.5.0}/LICENSE +0 -0
  83. {serenecode-0.4.0 → serenecode-0.5.0}/docs/SECURITY.md +0 -0
  84. {serenecode-0.4.0 → serenecode-0.5.0}/examples/DOSAGE_CALC_SPEC.md +0 -0
  85. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-regular/dosage_calc.py +0 -0
  86. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-regular/test_dosage_calc.py +0 -0
  87. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-serenecode/CLAUDE.md +0 -0
  88. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-serenecode/SERENECODE.md +0 -0
  89. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-serenecode/SPEC.md +0 -0
  90. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-serenecode/pyproject.toml +0 -0
  91. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-serenecode/src/dosage/__init__.py +0 -0
  92. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-serenecode/src/dosage/core/__init__.py +0 -0
  93. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-serenecode/src/dosage/core/dosage.py +0 -0
  94. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-serenecode/src/dosage/core/models.py +0 -0
  95. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-serenecode/src/dosage/core/safety.py +0 -0
  96. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-serenecode/tests/__init__.py +0 -0
  97. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-serenecode/tests/unit/__init__.py +0 -0
  98. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-serenecode/tests/unit/test_dosage.py +0 -0
  99. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-serenecode/tests/unit/test_models.py +0 -0
  100. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-serenecode/tests/unit/test_safety.py +0 -0
  101. {serenecode-0.4.0 → serenecode-0.5.0}/examples/dosage-serenecode/uv.lock +0 -0
  102. {serenecode-0.4.0 → serenecode-0.5.0}/serenecode.jpg +0 -0
  103. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/__init__.py +0 -0
  104. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/adapters/__init__.py +0 -0
  105. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/adapters/mypy_adapter.py +0 -0
  106. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/adapters/unavailable_dead_code_adapter.py +0 -0
  107. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/adapters/vulture_adapter.py +0 -0
  108. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/checker/__init__.py +0 -0
  109. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/checker/coverage.py +0 -0
  110. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/checker/properties.py +0 -0
  111. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/checker/types.py +0 -0
  112. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/contracts/__init__.py +0 -0
  113. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/core/__init__.py +0 -0
  114. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/mcp/__init__.py +0 -0
  115. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/mcp/resources.py +0 -0
  116. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/ports/__init__.py +0 -0
  117. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/ports/dead_code_analyzer.py +0 -0
  118. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/ports/property_tester.py +0 -0
  119. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/ports/symbolic_checker.py +0 -0
  120. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/ports/type_checker.py +0 -0
  121. {serenecode-0.4.0/tests → serenecode-0.5.0/src/serenecode/support}/__init__.py +0 -0
  122. {serenecode-0.4.0 → serenecode-0.5.0}/src/serenecode/templates/__init__.py +0 -0
  123. {serenecode-0.4.0/tests/e2e → serenecode-0.5.0/tests}/__init__.py +0 -0
  124. {serenecode-0.4.0 → serenecode-0.5.0}/tests/conftest.py +0 -0
  125. {serenecode-0.4.0/tests/integration → serenecode-0.5.0/tests/e2e}/__init__.py +0 -0
  126. {serenecode-0.4.0 → serenecode-0.5.0}/tests/e2e/test_check_command.py +0 -0
  127. {serenecode-0.4.0 → serenecode-0.5.0}/tests/e2e/test_cli.py +0 -0
  128. {serenecode-0.4.0 → serenecode-0.5.0}/tests/e2e/test_init.py +0 -0
  129. {serenecode-0.4.0 → serenecode-0.5.0}/tests/e2e/test_mcp_command.py +0 -0
  130. {serenecode-0.4.0 → serenecode-0.5.0}/tests/e2e/test_report_command.py +0 -0
  131. {serenecode-0.4.0 → serenecode-0.5.0}/tests/e2e/test_status_command.py +0 -0
  132. {serenecode-0.4.0 → serenecode-0.5.0}/tests/fixtures/edge_cases/aliased_import.py +0 -0
  133. {serenecode-0.4.0 → serenecode-0.5.0}/tests/fixtures/edge_cases/async_functions.py +0 -0
  134. {serenecode-0.4.0 → serenecode-0.5.0}/tests/fixtures/edge_cases/empty_module.py +0 -0
  135. {serenecode-0.4.0 → serenecode-0.5.0}/tests/fixtures/edge_cases/from_import.py +0 -0
  136. {serenecode-0.4.0 → serenecode-0.5.0}/tests/fixtures/invalid/broken_postcondition.py +0 -0
  137. {serenecode-0.4.0 → serenecode-0.5.0}/tests/fixtures/invalid/io_in_core.py +0 -0
  138. {serenecode-0.4.0 → serenecode-0.5.0}/tests/fixtures/invalid/missing_contracts.py +0 -0
  139. {serenecode-0.4.0 → serenecode-0.5.0}/tests/fixtures/invalid/missing_invariant.py +0 -0
  140. {serenecode-0.4.0 → serenecode-0.5.0}/tests/fixtures/invalid/missing_types.py +0 -0
  141. {serenecode-0.4.0 → serenecode-0.5.0}/tests/fixtures/valid/class_with_invariant.py +0 -0
  142. {serenecode-0.4.0 → serenecode-0.5.0}/tests/fixtures/valid/full_module.py +0 -0
  143. {serenecode-0.4.0 → serenecode-0.5.0}/tests/fixtures/valid/simple_function.py +0 -0
  144. {serenecode-0.4.0/tests/unit → serenecode-0.5.0/tests/integration}/__init__.py +0 -0
  145. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_checkers_real_code.py +0 -0
  146. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_coverage_adapter.py +0 -0
  147. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_crosshair_adapter.py +0 -0
  148. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_example_projects.py +0 -0
  149. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_file_adapter.py +0 -0
  150. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_hypothesis_adapter.py +0 -0
  151. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_local_fs.py +0 -0
  152. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_module_loader.py +0 -0
  153. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_mypy_adapter.py +0 -0
  154. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_resources.py +0 -0
  155. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_tools.py +0 -0
  156. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_unavailable_dead_code_adapter.py +0 -0
  157. {serenecode-0.4.0 → serenecode-0.5.0}/tests/integration/test_vulture_adapter.py +0 -0
  158. {serenecode-0.4.0/tests/unit/checker → serenecode-0.5.0/tests/unit}/__init__.py +0 -0
  159. {serenecode-0.4.0/tests/unit/contracts → serenecode-0.5.0/tests/unit/checker}/__init__.py +0 -0
  160. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/checker/test_compositional.py +0 -0
  161. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/checker/test_compositional_helpers.py +0 -0
  162. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/checker/test_coverage.py +0 -0
  163. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/checker/test_properties.py +0 -0
  164. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/checker/test_spec_traceability.py +0 -0
  165. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/checker/test_structural_hypothesis.py +0 -0
  166. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/checker/test_symbolic.py +0 -0
  167. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/checker/test_types.py +0 -0
  168. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/contracts/test_predicates.py +0 -0
  169. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/test_api.py +0 -0
  170. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/test_models_hypothesis.py +0 -0
  171. {serenecode-0.4.0 → serenecode-0.5.0}/tests/unit/test_source_discovery.py +0 -0
  172. {serenecode-0.4.0 → serenecode-0.5.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  ## Serenecode
2
2
 
3
- All code in this project MUST follow the standards defined in SERENECODE.md. Read SERENECODE.md before writing or modifying any code. Every public function must have icontract preconditions and postconditions. Every class with state must have invariants. Follow the architectural patterns specified in SERENECODE.md.
3
+ All code in this project MUST follow the same standards SereneCode ships to users: the embedded templates in `src/serenecode/templates/content.py` (default / strict / minimal) define the conventions the structural checker enforces. Read the relevant template before writing or modifying any code. Every public function must have icontract preconditions and postconditions. Every class with state must have invariants. Follow the architectural patterns specified there.
4
4
 
5
5
  Pre-existing `*_SPEC.md` or PRD files are narrative inputs; only project-root `SPEC.md` with REQ/INT identifiers satisfies SereneCode traceability (`serenecode check --spec`).
6
6
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: serenecode
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: Verification framework for AI-generated Python — test coverage, property testing, and symbolic execution
5
5
  Project-URL: Homepage, https://github.com/helgster77/serenecode
6
6
  Project-URL: Repository, https://github.com/helgster77/serenecode
@@ -51,7 +51,7 @@ SereneCode turns the question from "did the model ship code?" to "does it match
51
51
 
52
52
  **MCP:** register the server once (Claude Code, Cursor, Cline, Continue, or any MCP client) and the agent can pull structured JSON—findings, suggestions, counterexamples—while the cursor is still on the line, instead of discovering issues only after merge.
53
53
 
54
- > **This framework was bootstrapped with AI under its own rules.** SereneCode's SERENECODE.md was written before the first line of code, and the codebase has been developed under those conventions from the start — including the MCP server, which the same AI agents now use to verify their own work mid-edit. The current tree passes its own `serenecode check src --level 6 --allow-code-execution` end-to-end via the bare CLI (counts vary with the tree; expect hundreds of functions with a mix of passed, exempt, and advisory dead-code notes; wall time on the order of minutes for a full L1–L6 run), an internal strict-config Level 6 self-check in the test suite (`pytest tests/integration/test_example_projects.py::test_serenecode_repo_passes_strict_level_6`, which exercises L4–L6 against `strict_config` over the full source tree), `mypy src examples/dosage-serenecode/src`, the shipped dosage example's own `serenecode check src --level 6 --allow-code-execution`, and the full `pytest` suite (on the order of 1,400+ passing tests; a small number are skipped by design). The verification output is transparent about scope: exempt modules (adapters, CLI, ports, MCP server, `__init__.py`) and functions excluded from deep verification (non-primitive parameter types) are reported as "exempt" rather than silently omitted; dead-code findings are **advisories** and appear in the summary unless you use `--fail-on-advisory` to fail CI when any remain.
54
+ > **This framework was bootstrapped with AI under its own rules.** Convention templates in `src/serenecode/templates/content.py` were defined before the first line of code, and the codebase has been developed under those conventions from the start — including the MCP server, which the same AI agents now use to verify their own work mid-edit. The current tree passes its own `serenecode check src --level 6 --allow-code-execution` end-to-end via the bare CLI (counts vary with the tree; expect hundreds of functions with a mix of passed, exempt, and advisory notes; wall time on the order of minutes for a full L1–L6 run), an internal strict-config Level 6 self-check in the test suite (`pytest tests/integration/test_example_projects.py::test_serenecode_repo_passes_strict_level_6`, which exercises L4–L6 against `strict_config` over the full source tree), `mypy src examples/dosage-serenecode/src`, the shipped dosage example's own `serenecode check src --level 6 --allow-code-execution`, and the full `pytest` suite (on the order of 1,450+ passing tests; a small number are skipped by design). The verification output is transparent about scope: exempt modules (adapters, CLI, ports, MCP server, `__init__.py`) and functions excluded from deep verification (non-primitive parameter types) are reported as "exempt" rather than silently omitted; dead-code and module health findings are **advisories** and appear in the summary unless you use `--fail-on-advisory` to fail CI when any remain.
55
55
 
56
56
  ---
57
57
 
@@ -85,6 +85,8 @@ After enough hours pair-programming with coding agents, the same handful of mist
85
85
 
86
86
  - **Tests that pass but verify nothing.** A `def test_foo(): foo()` with no `assert` runs successfully and counts as "covered" — but it only checks that the function doesn't raise. L1's no-assertions-in-tests check fires on any `test_*` function with no `assert`, `pytest.raises`, `pytest.fail`, or `self.assertX` call.
87
87
 
88
+ - **Module bloat and god classes.** Agents accumulate code in a single module without splitting. A 2000-line file with 30 methods on one class compiles and tests pass, but it's unmaintainable. Module health checks flag files, functions, and classes that exceed configurable thresholds — advisory warnings when they're getting large, hard errors when they exceed the maximum. The agent gets concrete split suggestions derived from AST analysis: which classes could be standalone modules, which function groups share a prefix, and where banner comments suggest logical boundaries.
89
+
88
90
  - **Architectural drift.** Asked to "add a feature," the agent puts I/O in core, business logic in adapters, and circular imports between them. The system still works in tests because everything is loaded together — but the layering rule that made the code testable in the first place is gone. L6 compositional checks enforce dependency direction, interface compliance, and contract presence at module boundaries.
89
91
 
90
92
  None of these failures are unique to AI; humans make them too. What's unique is the *rate* at which an agent produces them and the *confidence* with which the agent reports the work as done. The structural checker, the contracts, the property tester, and the symbolic search exist to make each pattern impossible to ship without an explicit, reviewed override.
@@ -162,7 +164,7 @@ This creates SERENECODE.md (project conventions including spec traceability) and
162
164
 
163
165
  A lightweight AST-based checker that validates code follows SERENECODE.md conventions in seconds. Missing a postcondition? No class invariant? No test file for a module? Caught before you waste time on heavy verification.
164
166
 
165
- L1 also catches AI-failure-mode patterns that compile and look correct but represent real bugs: stub residue (`pass`/`...`/`raise NotImplementedError` left as a function body), mutable default arguments, bare `assert` in non-test source, `print()` in core, dangerous calls (`eval`, `exec`, `pickle.loads`, `os.system`, `subprocess` with `shell=True`), `TODO`/`FIXME`/`XXX`/`HACK` markers in tracked files, tests with no assertions, silent exception handlers, tautological postconditions, and likely dead code. Dead-code findings are advisory review items: the agent should ask the user whether to remove or allowlist the code before changing it. Each rule has a per-rule opt-out comment for legitimate exceptions; see SERENECODE.md "Code Quality Standards" for the full list.
167
+ L1 also catches AI-failure-mode patterns that compile and look correct but represent real bugs: stub residue (`pass`/`...`/`raise NotImplementedError` left as a function body), mutable default arguments, bare `assert` in non-test source, `print()` in core, dangerous calls (`eval`, `exec`, `pickle.loads`, `os.system`, `subprocess` with `shell=True`), `TODO`/`FIXME`/`XXX`/`HACK` markers in tracked files, tests with no assertions, silent exception handlers, tautological postconditions, and likely dead code. L1 additionally runs **module health checks**: files exceeding a configurable line threshold, functions that are too long, functions with too many parameters, and classes with too many methods generate warnings (advisory) or errors depending on severity. These target the common AI agent drift pattern of accumulating code in a single module without splitting. Dead-code and module health findings are advisory review items; each rule has a per-rule opt-out comment for legitimate exceptions. See SERENECODE.md "Code Quality Standards" and "Module Health" for the full list. Skip all module health checks with `--skip-module-health`.
166
168
 
167
169
  ```bash
168
170
  serenecode check src/ --structural # structural conventions + dead-code review
@@ -228,8 +230,9 @@ The same `serenecode mcp` stdio server works in Claude Code, Cursor, Cline, Cont
228
230
  | `serenecode_integration_status` | Implementation/verification status of one INT |
229
231
  | `serenecode_orphans` | REQs with no implementation or no test |
230
232
  | `serenecode_dead_code` | Likely dead-code findings that require user review |
233
+ | `serenecode_module_health` | Module health metrics (file size, function lengths, parameter counts, class sizes) for a single file — no verification needed |
231
234
 
232
- Tool results mirror the CLI pipeline: structured payloads include **`passed`**, levels, **`verdict`**, and a **summary** with counts (including **`advisory_count`** for dead-code-style exempt rows). Paths and `project_root` are resolved on the host — they are not sandboxed to one workspace; see [docs/SECURITY.md](docs/SECURITY.md).
235
+ Tool results mirror the CLI pipeline: structured payloads include **`passed`**, levels, **`verdict`**, and a **summary** with counts (including **`advisory_count`** for advisory findings like dead code and module health warnings). Paths and `project_root` are resolved on the host — they are not sandboxed to one workspace; see [docs/SECURITY.md](docs/SECURITY.md).
233
236
 
234
237
  **Read-only resources** the agent can fetch without "calling" anything: `serenecode://config` (active SerenecodeConfig as JSON), `serenecode://findings/last-run` (most recent CheckResponse from this server session), `serenecode://exempt-modules` (the exempt path patterns for the active config), `serenecode://reqs` (parsed REQ-xxx list from the project's SPEC.md), and `serenecode://integrations` (parsed INT-xxx metadata from the project's SPEC.md).
235
238
 
@@ -310,13 +313,13 @@ The library API (`serenecode.check`) and the MCP server (`serenecode_check`, `se
310
313
 
311
314
  SereneCode isn't just a tool that *tells* you to write verified code. It *is* verified code.
312
315
 
313
- The SERENECODE.md convention file was the first artifact created — before any Python was written. The framework has been developed under those conventions with AI as a first-class contributor, and the repository continuously checks itself with:
316
+ Those convention templates were the first artifacts — before any Python was written. The framework has been developed under those conventions with AI as a first-class contributor, and the repository continuously checks itself with:
314
317
 
315
- - `pytest` across the full suite (on the order of 1,400+ passing tests; a small number skipped by design)
318
+ - `pytest` across the full suite (on the order of 1,450+ passing tests; a small number skipped by design)
316
319
  - `mypy --strict` across `src/` and `examples/dosage-serenecode/src/`
317
320
  - SereneCode's own structural, type, property, symbolic, and compositional passes
318
321
 
319
- On the current tree, `serenecode check src --level 6 --allow-code-execution` runs the full L1–L6 pipeline against the framework's own source; exact counts of passed / exempt / advisory rows change as the tree grows (wall time often several minutes for a deep run). A separate integration test, `test_serenecode_repo_passes_strict_level_6`, runs the same `src/` tree through `run_pipeline` with `strict_config()` and `start_level=4`, which strips path-based exemptions and forces adapters, CLI, MCP, and similar code through L4–L6. The exempt items in a **default-config** run still include adapter modules, port `Protocol`s, CLI/MCP composition roots, and functions whose parameter types are poor fits for Hypothesis/CrossHair. Exempt and advisory rows stay visible in the output — they are not silently omitted.
322
+ On the current tree, `serenecode check src --level 6 --allow-code-execution` runs the full L1–L6 pipeline against the framework's own source; exact counts of passed / exempt / advisory rows change as the tree grows (wall time often several minutes for a deep run). A separate integration test, `test_serenecode_repo_passes_strict_level_6`, runs the same `src/` tree through `run_pipeline` with `strict_config()` and `start_level=4`, which strips path-based exemptions and forces adapters, CLI, MCP, and similar code through L4–L6. The exempt items in a **default-config** run still include adapter modules, port `Protocol`s, CLI/MCP composition roots, and functions whose parameter types are poor fits for Hypothesis/CrossHair. Advisory items include dead-code findings and module health warnings (file length, function length, parameter count, class method count). Exempt and advisory rows stay visible in the output — they are not silently omitted.
320
323
 
321
324
  At Level 5, CrossHair and Z3 search for counterexamples across the codebase's symbolic-friendly contracted top-level functions. Functions with non-primitive parameters (custom dataclasses, Protocol implementations, Callable types) are reported as exempt because the solver cannot generate inputs for them. Level 6 adds structural compositional analysis: dependency direction, circular dependency detection, interface compliance, contract presence at module boundaries, aliased cross-module call resolution, and architectural invariants. Interface compliance follows explicit `Protocol` inheritance and checks substitutability, including extra required parameters and incompatible return annotations. Together, they provide both deep per-function verification and system-level structural guarantees — but the structural checks at L6 verify contract *presence*, not logical *sufficiency* across call chains.
322
325
 
@@ -365,7 +368,8 @@ serenecode check [<path>] [--level 1-6] [--allow-code-execution] # run ve
365
368
  [--project-root DIR] # repo root for imports + config
366
369
  [--format human|json] # output format
367
370
  [--structural] [--verify] # L1 only / L3-6 only
368
- [--fail-on-advisory] # exit 11 if dead-code advisories remain
371
+ [--skip-module-health] # skip file/function/param/class size checks
372
+ [--fail-on-advisory] # exit 11 if advisories remain
369
373
  [--per-condition-timeout N] # L5 CrossHair budgets
370
374
  [--per-path-timeout N] [--module-timeout N] # (defaults: 30/10/300s)
371
375
  [--coverage-timeout N] # L3 pytest/coverage subprocess (default 600s)
@@ -379,7 +383,7 @@ serenecode mcp [--allow-code-execution] # boot t
379
383
 
380
384
  **Environment (optional):** `SERENECODE_MAX_WORKERS` overrides `--workers`; `SERENECODE_COVERAGE_TIMEOUT` overrides `--coverage-timeout`. **`SERENECODE_DEBUG=1`** logs subprocess environment **key names** (not values) when tools spawn mypy, pytest, CrossHair, etc. Details: [docs/SECURITY.md](docs/SECURITY.md).
381
385
 
382
- **Exit codes:** 0 = passed (and no `--fail-on-advisory` violation), 1–6 = first failing verification level (structural … compositional), 10 = internal error or deep verification refused without `--allow-code-execution`, **11 = dead-code advisories remain with `--fail-on-advisory`** (checks otherwise passed).
386
+ **Exit codes:** 0 = passed (and no `--fail-on-advisory` violation), 1–6 = first failing verification level (structural … compositional), 10 = internal error or deep verification refused without `--allow-code-execution`, **11 = advisories remain with `--fail-on-advisory`** (dead code, module health warnings; checks otherwise passed).
383
387
 
384
388
  ---
385
389
 
@@ -391,7 +395,7 @@ SereneCode is honest about what it can and can't do:
391
395
 
392
396
  **Contracts are only as good as you write them.** A function with weak postconditions will pass verification even if the implementation is subtly wrong. SereneCode checks that contracts exist and hold, but can't check that they fully capture your intent. Tautological contracts like `lambda self: True` are now flagged by the conventions and should not be used — they provide no verification value.
393
397
 
394
- **Exempt items are visible, not hidden.** Modules exempt from structural checking (adapters, CLI, ports, MCP server, `__init__.py`) and functions excluded from deep verification (non-primitive parameter types, adapter code) are reported as "exempt" in the output rather than being silently omitted. This makes the verification scope transparent: the tool reports passed, failed, skipped, and exempt counts separately so you can see exactly what was and wasn't deeply verified. Previous versions silently omitted these, inflating the apparent scope.
398
+ **Exempt items are visible, not hidden.** Modules exempt from structural checking (adapters, CLI, ports, MCP server, `__init__.py`) and functions excluded from deep verification (non-primitive parameter types, adapter code) are reported as "exempt" in the output rather than being silently omitted. Advisory items (dead code, module health warnings) are also visible and counted separately. This makes the verification scope transparent: the tool reports passed, failed, skipped, exempt, and advisory counts separately so you can see exactly what was and wasn't deeply verified.
395
399
 
396
400
  **Runtime checks can be disabled.** icontract decorators are checked on every call by default, but can be disabled via environment variables for performance in production. This is a feature, not a bug — but it means runtime guarantees depend on configuration.
397
401
 
@@ -419,6 +423,7 @@ CLI / Library API / MCP ← composition roots (interactive init, spec valida
419
423
  │ ├──▸ Structural Checker (ast)
420
424
  │ ├──▸ Spec Traceability (REQ-xxx / INT-xxx → Implements/Verifies)
421
425
  │ ├──▸ Dead-Code Review (likely unused code → ask before removal)
426
+ │ ├──▸ Module Health (file/function/class size → advisory or error)
422
427
  │ ├──▸ Test Existence (test_<module>.py discovery)
423
428
  │ ├──▸ Type Checker (mypy)
424
429
  │ ├──▸ Coverage Analyzer (coverage.py)
@@ -433,6 +438,16 @@ CLI / Library API / MCP ← composition roots (interactive init, spec valida
433
438
 
434
439
  Core logic is pure. All I/O goes through Protocol-defined ports. The verification engine itself is verifiable.
435
440
 
441
+ ## Comparison: AWS Kiro and Spec Kit / Speckit
442
+
443
+ SereneCode overlaps with these tools on **spec-first, AI-assisted development**—all three push against unstructured “vibe coding.” The difference is **what each product optimizes for**.
444
+
445
+ **AWS Kiro** is an agentic AI IDE from AWS (Bedrock-powered), with spec-driven flows, autonomous agents, “powers,” and multi-repo work inside that environment. SereneCode is **not an IDE**: it is a **Python verification toolkit** (CLI + MCP) that plugs into editors you already use. Kiro optimizes **how you build in their stack**; SereneCode optimizes **repeatable assurance on Python code**—traceability from root `SPEC.md` IDs to implementation and tests, `icontract` contracts, mypy, coverage, Hypothesis, bounded CrossHair search, and compositional checks. The two are **complementary** if you use Kiro to author code but still want repo-local, machine-checkable verification on a Python tree.
446
+
447
+ **Spec Kit** (GitHub’s methodology) and ecosystem tools such as **Speckit** focus on **structured specification and phased delivery**—for example constitution, specify, plan, tasks, and implementation—with agents and templates driving the workflow. “Executable” there often means **process and artifact structure** that steers implementation. SereneCode adds a different meaning of executable: **contracts and checkers that run against your Python**, plus optional solvers and property tests, with explicit **REQ-xxx / INT-xxx** traceability to `Implements:` / `Verifies:` in code and tests. Spec Kit is typically **stack-agnostic**; SereneCode is **Python-specific** by design.
448
+
449
+ If you already use Spec Kit–style phases, SereneCode fits **after** the spec is stable enough to land as root `SPEC.md`—as the **verification layer** that answers whether the code and tests actually match what you declared.
450
+
436
451
  ## Security and trust
437
452
 
438
453
  Serenecode runs on **your machine** and, with `--allow-code-execution` (CLI or MCP), **imports and executes** project code—similar trust to running `pytest` or `python -m` on that tree. It is **not** a sandbox. Subprocesses receive a filtered environment to limit credential leakage; see [docs/SECURITY.md](docs/SECURITY.md) for the threat model, MCP behavior, `SERENECODE_DEBUG`, and CI exit code **11** with `--fail-on-advisory`.
@@ -15,7 +15,7 @@ SereneCode turns the question from "did the model ship code?" to "does it match
15
15
 
16
16
  **MCP:** register the server once (Claude Code, Cursor, Cline, Continue, or any MCP client) and the agent can pull structured JSON—findings, suggestions, counterexamples—while the cursor is still on the line, instead of discovering issues only after merge.
17
17
 
18
- > **This framework was bootstrapped with AI under its own rules.** SereneCode's SERENECODE.md was written before the first line of code, and the codebase has been developed under those conventions from the start — including the MCP server, which the same AI agents now use to verify their own work mid-edit. The current tree passes its own `serenecode check src --level 6 --allow-code-execution` end-to-end via the bare CLI (counts vary with the tree; expect hundreds of functions with a mix of passed, exempt, and advisory dead-code notes; wall time on the order of minutes for a full L1–L6 run), an internal strict-config Level 6 self-check in the test suite (`pytest tests/integration/test_example_projects.py::test_serenecode_repo_passes_strict_level_6`, which exercises L4–L6 against `strict_config` over the full source tree), `mypy src examples/dosage-serenecode/src`, the shipped dosage example's own `serenecode check src --level 6 --allow-code-execution`, and the full `pytest` suite (on the order of 1,400+ passing tests; a small number are skipped by design). The verification output is transparent about scope: exempt modules (adapters, CLI, ports, MCP server, `__init__.py`) and functions excluded from deep verification (non-primitive parameter types) are reported as "exempt" rather than silently omitted; dead-code findings are **advisories** and appear in the summary unless you use `--fail-on-advisory` to fail CI when any remain.
18
+ > **This framework was bootstrapped with AI under its own rules.** Convention templates in `src/serenecode/templates/content.py` were defined before the first line of code, and the codebase has been developed under those conventions from the start — including the MCP server, which the same AI agents now use to verify their own work mid-edit. The current tree passes its own `serenecode check src --level 6 --allow-code-execution` end-to-end via the bare CLI (counts vary with the tree; expect hundreds of functions with a mix of passed, exempt, and advisory notes; wall time on the order of minutes for a full L1–L6 run), an internal strict-config Level 6 self-check in the test suite (`pytest tests/integration/test_example_projects.py::test_serenecode_repo_passes_strict_level_6`, which exercises L4–L6 against `strict_config` over the full source tree), `mypy src examples/dosage-serenecode/src`, the shipped dosage example's own `serenecode check src --level 6 --allow-code-execution`, and the full `pytest` suite (on the order of 1,450+ passing tests; a small number are skipped by design). The verification output is transparent about scope: exempt modules (adapters, CLI, ports, MCP server, `__init__.py`) and functions excluded from deep verification (non-primitive parameter types) are reported as "exempt" rather than silently omitted; dead-code and module health findings are **advisories** and appear in the summary unless you use `--fail-on-advisory` to fail CI when any remain.
19
19
 
20
20
  ---
21
21
 
@@ -49,6 +49,8 @@ After enough hours pair-programming with coding agents, the same handful of mist
49
49
 
50
50
  - **Tests that pass but verify nothing.** A `def test_foo(): foo()` with no `assert` runs successfully and counts as "covered" — but it only checks that the function doesn't raise. L1's no-assertions-in-tests check fires on any `test_*` function with no `assert`, `pytest.raises`, `pytest.fail`, or `self.assertX` call.
51
51
 
52
+ - **Module bloat and god classes.** Agents accumulate code in a single module without splitting. A 2000-line file with 30 methods on one class compiles and tests pass, but it's unmaintainable. Module health checks flag files, functions, and classes that exceed configurable thresholds — advisory warnings when they're getting large, hard errors when they exceed the maximum. The agent gets concrete split suggestions derived from AST analysis: which classes could be standalone modules, which function groups share a prefix, and where banner comments suggest logical boundaries.
53
+
52
54
  - **Architectural drift.** Asked to "add a feature," the agent puts I/O in core, business logic in adapters, and circular imports between them. The system still works in tests because everything is loaded together — but the layering rule that made the code testable in the first place is gone. L6 compositional checks enforce dependency direction, interface compliance, and contract presence at module boundaries.
53
55
 
54
56
  None of these failures are unique to AI; humans make them too. What's unique is the *rate* at which an agent produces them and the *confidence* with which the agent reports the work as done. The structural checker, the contracts, the property tester, and the symbolic search exist to make each pattern impossible to ship without an explicit, reviewed override.
@@ -126,7 +128,7 @@ This creates SERENECODE.md (project conventions including spec traceability) and
126
128
 
127
129
  A lightweight AST-based checker that validates code follows SERENECODE.md conventions in seconds. Missing a postcondition? No class invariant? No test file for a module? Caught before you waste time on heavy verification.
128
130
 
129
- L1 also catches AI-failure-mode patterns that compile and look correct but represent real bugs: stub residue (`pass`/`...`/`raise NotImplementedError` left as a function body), mutable default arguments, bare `assert` in non-test source, `print()` in core, dangerous calls (`eval`, `exec`, `pickle.loads`, `os.system`, `subprocess` with `shell=True`), `TODO`/`FIXME`/`XXX`/`HACK` markers in tracked files, tests with no assertions, silent exception handlers, tautological postconditions, and likely dead code. Dead-code findings are advisory review items: the agent should ask the user whether to remove or allowlist the code before changing it. Each rule has a per-rule opt-out comment for legitimate exceptions; see SERENECODE.md "Code Quality Standards" for the full list.
131
+ L1 also catches AI-failure-mode patterns that compile and look correct but represent real bugs: stub residue (`pass`/`...`/`raise NotImplementedError` left as a function body), mutable default arguments, bare `assert` in non-test source, `print()` in core, dangerous calls (`eval`, `exec`, `pickle.loads`, `os.system`, `subprocess` with `shell=True`), `TODO`/`FIXME`/`XXX`/`HACK` markers in tracked files, tests with no assertions, silent exception handlers, tautological postconditions, and likely dead code. L1 additionally runs **module health checks**: files exceeding a configurable line threshold, functions that are too long, functions with too many parameters, and classes with too many methods generate warnings (advisory) or errors depending on severity. These target the common AI agent drift pattern of accumulating code in a single module without splitting. Dead-code and module health findings are advisory review items; each rule has a per-rule opt-out comment for legitimate exceptions. See SERENECODE.md "Code Quality Standards" and "Module Health" for the full list. Skip all module health checks with `--skip-module-health`.
130
132
 
131
133
  ```bash
132
134
  serenecode check src/ --structural # structural conventions + dead-code review
@@ -192,8 +194,9 @@ The same `serenecode mcp` stdio server works in Claude Code, Cursor, Cline, Cont
192
194
  | `serenecode_integration_status` | Implementation/verification status of one INT |
193
195
  | `serenecode_orphans` | REQs with no implementation or no test |
194
196
  | `serenecode_dead_code` | Likely dead-code findings that require user review |
197
+ | `serenecode_module_health` | Module health metrics (file size, function lengths, parameter counts, class sizes) for a single file — no verification needed |
195
198
 
196
- Tool results mirror the CLI pipeline: structured payloads include **`passed`**, levels, **`verdict`**, and a **summary** with counts (including **`advisory_count`** for dead-code-style exempt rows). Paths and `project_root` are resolved on the host — they are not sandboxed to one workspace; see [docs/SECURITY.md](docs/SECURITY.md).
199
+ Tool results mirror the CLI pipeline: structured payloads include **`passed`**, levels, **`verdict`**, and a **summary** with counts (including **`advisory_count`** for advisory findings like dead code and module health warnings). Paths and `project_root` are resolved on the host — they are not sandboxed to one workspace; see [docs/SECURITY.md](docs/SECURITY.md).
197
200
 
198
201
  **Read-only resources** the agent can fetch without "calling" anything: `serenecode://config` (active SerenecodeConfig as JSON), `serenecode://findings/last-run` (most recent CheckResponse from this server session), `serenecode://exempt-modules` (the exempt path patterns for the active config), `serenecode://reqs` (parsed REQ-xxx list from the project's SPEC.md), and `serenecode://integrations` (parsed INT-xxx metadata from the project's SPEC.md).
199
202
 
@@ -274,13 +277,13 @@ The library API (`serenecode.check`) and the MCP server (`serenecode_check`, `se
274
277
 
275
278
  SereneCode isn't just a tool that *tells* you to write verified code. It *is* verified code.
276
279
 
277
- The SERENECODE.md convention file was the first artifact created — before any Python was written. The framework has been developed under those conventions with AI as a first-class contributor, and the repository continuously checks itself with:
280
+ Those convention templates were the first artifacts — before any Python was written. The framework has been developed under those conventions with AI as a first-class contributor, and the repository continuously checks itself with:
278
281
 
279
- - `pytest` across the full suite (on the order of 1,400+ passing tests; a small number skipped by design)
282
+ - `pytest` across the full suite (on the order of 1,450+ passing tests; a small number skipped by design)
280
283
  - `mypy --strict` across `src/` and `examples/dosage-serenecode/src/`
281
284
  - SereneCode's own structural, type, property, symbolic, and compositional passes
282
285
 
283
- On the current tree, `serenecode check src --level 6 --allow-code-execution` runs the full L1–L6 pipeline against the framework's own source; exact counts of passed / exempt / advisory rows change as the tree grows (wall time often several minutes for a deep run). A separate integration test, `test_serenecode_repo_passes_strict_level_6`, runs the same `src/` tree through `run_pipeline` with `strict_config()` and `start_level=4`, which strips path-based exemptions and forces adapters, CLI, MCP, and similar code through L4–L6. The exempt items in a **default-config** run still include adapter modules, port `Protocol`s, CLI/MCP composition roots, and functions whose parameter types are poor fits for Hypothesis/CrossHair. Exempt and advisory rows stay visible in the output — they are not silently omitted.
286
+ On the current tree, `serenecode check src --level 6 --allow-code-execution` runs the full L1–L6 pipeline against the framework's own source; exact counts of passed / exempt / advisory rows change as the tree grows (wall time often several minutes for a deep run). A separate integration test, `test_serenecode_repo_passes_strict_level_6`, runs the same `src/` tree through `run_pipeline` with `strict_config()` and `start_level=4`, which strips path-based exemptions and forces adapters, CLI, MCP, and similar code through L4–L6. The exempt items in a **default-config** run still include adapter modules, port `Protocol`s, CLI/MCP composition roots, and functions whose parameter types are poor fits for Hypothesis/CrossHair. Advisory items include dead-code findings and module health warnings (file length, function length, parameter count, class method count). Exempt and advisory rows stay visible in the output — they are not silently omitted.
284
287
 
285
288
  At Level 5, CrossHair and Z3 search for counterexamples across the codebase's symbolic-friendly contracted top-level functions. Functions with non-primitive parameters (custom dataclasses, Protocol implementations, Callable types) are reported as exempt because the solver cannot generate inputs for them. Level 6 adds structural compositional analysis: dependency direction, circular dependency detection, interface compliance, contract presence at module boundaries, aliased cross-module call resolution, and architectural invariants. Interface compliance follows explicit `Protocol` inheritance and checks substitutability, including extra required parameters and incompatible return annotations. Together, they provide both deep per-function verification and system-level structural guarantees — but the structural checks at L6 verify contract *presence*, not logical *sufficiency* across call chains.
286
289
 
@@ -329,7 +332,8 @@ serenecode check [<path>] [--level 1-6] [--allow-code-execution] # run ve
329
332
  [--project-root DIR] # repo root for imports + config
330
333
  [--format human|json] # output format
331
334
  [--structural] [--verify] # L1 only / L3-6 only
332
- [--fail-on-advisory] # exit 11 if dead-code advisories remain
335
+ [--skip-module-health] # skip file/function/param/class size checks
336
+ [--fail-on-advisory] # exit 11 if advisories remain
333
337
  [--per-condition-timeout N] # L5 CrossHair budgets
334
338
  [--per-path-timeout N] [--module-timeout N] # (defaults: 30/10/300s)
335
339
  [--coverage-timeout N] # L3 pytest/coverage subprocess (default 600s)
@@ -343,7 +347,7 @@ serenecode mcp [--allow-code-execution] # boot t
343
347
 
344
348
  **Environment (optional):** `SERENECODE_MAX_WORKERS` overrides `--workers`; `SERENECODE_COVERAGE_TIMEOUT` overrides `--coverage-timeout`. **`SERENECODE_DEBUG=1`** logs subprocess environment **key names** (not values) when tools spawn mypy, pytest, CrossHair, etc. Details: [docs/SECURITY.md](docs/SECURITY.md).
345
349
 
346
- **Exit codes:** 0 = passed (and no `--fail-on-advisory` violation), 1–6 = first failing verification level (structural … compositional), 10 = internal error or deep verification refused without `--allow-code-execution`, **11 = dead-code advisories remain with `--fail-on-advisory`** (checks otherwise passed).
350
+ **Exit codes:** 0 = passed (and no `--fail-on-advisory` violation), 1–6 = first failing verification level (structural … compositional), 10 = internal error or deep verification refused without `--allow-code-execution`, **11 = advisories remain with `--fail-on-advisory`** (dead code, module health warnings; checks otherwise passed).
347
351
 
348
352
  ---
349
353
 
@@ -355,7 +359,7 @@ SereneCode is honest about what it can and can't do:
355
359
 
356
360
  **Contracts are only as good as you write them.** A function with weak postconditions will pass verification even if the implementation is subtly wrong. SereneCode checks that contracts exist and hold, but can't check that they fully capture your intent. Tautological contracts like `lambda self: True` are now flagged by the conventions and should not be used — they provide no verification value.
357
361
 
358
- **Exempt items are visible, not hidden.** Modules exempt from structural checking (adapters, CLI, ports, MCP server, `__init__.py`) and functions excluded from deep verification (non-primitive parameter types, adapter code) are reported as "exempt" in the output rather than being silently omitted. This makes the verification scope transparent: the tool reports passed, failed, skipped, and exempt counts separately so you can see exactly what was and wasn't deeply verified. Previous versions silently omitted these, inflating the apparent scope.
362
+ **Exempt items are visible, not hidden.** Modules exempt from structural checking (adapters, CLI, ports, MCP server, `__init__.py`) and functions excluded from deep verification (non-primitive parameter types, adapter code) are reported as "exempt" in the output rather than being silently omitted. Advisory items (dead code, module health warnings) are also visible and counted separately. This makes the verification scope transparent: the tool reports passed, failed, skipped, exempt, and advisory counts separately so you can see exactly what was and wasn't deeply verified.
359
363
 
360
364
  **Runtime checks can be disabled.** icontract decorators are checked on every call by default, but can be disabled via environment variables for performance in production. This is a feature, not a bug — but it means runtime guarantees depend on configuration.
361
365
 
@@ -383,6 +387,7 @@ CLI / Library API / MCP ← composition roots (interactive init, spec valida
383
387
  │ ├──▸ Structural Checker (ast)
384
388
  │ ├──▸ Spec Traceability (REQ-xxx / INT-xxx → Implements/Verifies)
385
389
  │ ├──▸ Dead-Code Review (likely unused code → ask before removal)
390
+ │ ├──▸ Module Health (file/function/class size → advisory or error)
386
391
  │ ├──▸ Test Existence (test_<module>.py discovery)
387
392
  │ ├──▸ Type Checker (mypy)
388
393
  │ ├──▸ Coverage Analyzer (coverage.py)
@@ -397,6 +402,16 @@ CLI / Library API / MCP ← composition roots (interactive init, spec valida
397
402
 
398
403
  Core logic is pure. All I/O goes through Protocol-defined ports. The verification engine itself is verifiable.
399
404
 
405
+ ## Comparison: AWS Kiro and Spec Kit / Speckit
406
+
407
+ SereneCode overlaps with these tools on **spec-first, AI-assisted development**—all three push against unstructured “vibe coding.” The difference is **what each product optimizes for**.
408
+
409
+ **AWS Kiro** is an agentic AI IDE from AWS (Bedrock-powered), with spec-driven flows, autonomous agents, “powers,” and multi-repo work inside that environment. SereneCode is **not an IDE**: it is a **Python verification toolkit** (CLI + MCP) that plugs into editors you already use. Kiro optimizes **how you build in their stack**; SereneCode optimizes **repeatable assurance on Python code**—traceability from root `SPEC.md` IDs to implementation and tests, `icontract` contracts, mypy, coverage, Hypothesis, bounded CrossHair search, and compositional checks. The two are **complementary** if you use Kiro to author code but still want repo-local, machine-checkable verification on a Python tree.
410
+
411
+ **Spec Kit** (GitHub’s methodology) and ecosystem tools such as **Speckit** focus on **structured specification and phased delivery**—for example constitution, specify, plan, tasks, and implementation—with agents and templates driving the workflow. “Executable” there often means **process and artifact structure** that steers implementation. SereneCode adds a different meaning of executable: **contracts and checkers that run against your Python**, plus optional solvers and property tests, with explicit **REQ-xxx / INT-xxx** traceability to `Implements:` / `Verifies:` in code and tests. Spec Kit is typically **stack-agnostic**; SereneCode is **Python-specific** by design.
412
+
413
+ If you already use Spec Kit–style phases, SereneCode fits **after** the spec is stable enough to land as root `SPEC.md`—as the **verification layer** that answers whether the code and tests actually match what you declared.
414
+
400
415
  ## Security and trust
401
416
 
402
417
  Serenecode runs on **your machine** and, with `--allow-code-execution` (CLI or MCP), **imports and executes** project code—similar trust to running `pytest` or `python -m` on that tree. It is **not** a sandbox. Subprocesses receive a filtered environment to limit credential leakage; see [docs/SECURITY.md](docs/SECURITY.md) for the threat model, MCP behavior, `SERENECODE_DEBUG`, and CI exit code **11** with `--fail-on-advisory`.
@@ -0,0 +1,290 @@
1
+ # Module Health Checks — Specification
2
+
3
+ **Purpose:** Extend SereneCode with structural checks that detect overgrown files, functions, classes, and parameter lists — common AI coding agent failure modes — and provide actionable refactoring guidance.
4
+
5
+ **Source:** Implementation plan derived from codebase exploration (2026-04-13).
6
+
7
+ ---
8
+
9
+ ## Configuration
10
+
11
+ ### REQ-001: ModuleHealthConfig dataclass
12
+
13
+ A `ModuleHealthConfig` frozen dataclass with the following fields, all enforced by class invariants:
14
+
15
+ - `enabled`: bool. When False, all module health checks are skipped.
16
+ - `file_length_warn`: int, lines above which a file-length advisory is emitted. Must be > 0.
17
+ - `file_length_error`: int, lines above which a file-length error is emitted. Must be > `file_length_warn`.
18
+ - `function_length_warn`: int, body lines above which a function-length advisory is emitted. Must be > 0.
19
+ - `function_length_error`: int, body lines above which a function-length error is emitted. Must be > `function_length_warn`.
20
+ - `parameter_count_warn`: int, non-receiver parameters above which an advisory is emitted. Must be > 0.
21
+ - `parameter_count_error`: int, non-receiver parameters above which an error is emitted. Must be > `parameter_count_warn`.
22
+ - `class_method_count_warn`: int, methods above which a class-size advisory is emitted. Must be > 0.
23
+ - `class_method_count_error`: int, methods above which a class-size error is emitted. Must be > `class_method_count_warn`.
24
+
25
+ ### REQ-002: ModuleHealthConfig added to SerenecodeConfig
26
+
27
+ `SerenecodeConfig` gains a `module_health: ModuleHealthConfig` field. All existing composition roots (`default_config`, `strict_config`, `minimal_config`, `_apply_content_overrides`) must propagate this field.
28
+
29
+ ### REQ-003: Template-specific default thresholds
30
+
31
+ Each template preset provides different thresholds:
32
+
33
+ | Metric | Default (warn / error) | Strict (warn / error) | Minimal (warn / error) |
34
+ |-----------------------|------------------------|-----------------------|------------------------|
35
+ | File length (lines) | 500 / 1000 | 400 / 700 | 750 / 1500 |
36
+ | Function length (lines) | 50 / 100 | 30 / 60 | 75 / 150 |
37
+ | Parameter count | 5 / 8 | 4 / 6 | 7 / 10 |
38
+ | Class method count | 15 / 25 | 10 / 18 | 20 / 35 |
39
+
40
+ ---
41
+
42
+ ## Advisory Generalization
43
+
44
+ ### REQ-004: ADVISORY_FINDING_TYPES constant
45
+
46
+ A module-level `frozenset[str]` in `models.py` enumerating all finding types that use the advisory pattern (EXEMPT status, visible in output, do not block verification unless `--fail-on-advisory`). Initial members: `"dead_code"`, `"file_length"`, `"function_length"`, `"parameter_count"`, `"class_method_count"`.
47
+
48
+ ### REQ-005: Generalized advisory counting in make_check_result
49
+
50
+ `make_check_result()` must count advisory results by checking `detail.finding_type in ADVISORY_FINDING_TYPES` instead of hardcoding `"dead_code"`. The `advisory_count` field in `CheckSummary` must reflect all advisory types.
51
+
52
+ ### REQ-006: Generalized advisory display in reporter
53
+
54
+ The human and HTML reporters must classify advisory results using `ADVISORY_FINDING_TYPES` membership instead of hardcoding `"dead_code"`. The summary label must read `"advisory"` (not `"advisory (dead code)"`).
55
+
56
+ ### REQ-007: Generalized advisory inclusion in MCP wire format
57
+
58
+ The `to_check_response` projection in `schemas.py` must include EXEMPT results with any `finding_type in ADVISORY_FINDING_TYPES` in the wire findings, not only `"dead_code"`.
59
+
60
+ ---
61
+
62
+ ## File Length Check
63
+
64
+ ### REQ-008: File length check counts total lines
65
+
66
+ `_check_file_length` counts lines as `len(source.splitlines())` for each source file. Test files (identified by `_is_test_file_path`) are excluded.
67
+
68
+ ### REQ-009: File length error when exceeding error threshold
69
+
70
+ When line count exceeds `config.module_health.file_length_error`, a `FunctionResult` with `status=FAILED`, `function="<module>"`, `line=1`, `finding_type="file_length"` is emitted. The message must include the actual line count and the threshold.
71
+
72
+ ### REQ-010: File length advisory when exceeding warn threshold
73
+
74
+ When line count exceeds `config.module_health.file_length_warn` but not the error threshold, a `FunctionResult` with `status=EXEMPT`, `finding_type="file_length"` is emitted (advisory pattern). The message must include the actual line count and both thresholds.
75
+
76
+ ### REQ-011: File length check runs on exempt modules
77
+
78
+ Unlike structural policy checks, file length runs on all source files including modules exempt from contract/type checks. This is because exempt modules (adapters, CLI, MCP tools) are often the largest files.
79
+
80
+ ### REQ-012: File length suggestions are agent-actionable
81
+
82
+ The `suggestion` field for file-length findings must include concrete refactoring strategies: extracting classes into standalone modules, grouping related functions by shared prefix or domain concept, and identifying comment-banner section boundaries.
83
+
84
+ ---
85
+
86
+ ## Function Length Check
87
+
88
+ ### REQ-013: Function length measured by line span
89
+
90
+ `_check_function_length` measures each function's length as `node.end_lineno - node.lineno + 1` using AST `end_lineno`. Both `FunctionDef` and `AsyncFunctionDef` at module level and as class methods are checked.
91
+
92
+ ### REQ-014: Function length error when exceeding error threshold
93
+
94
+ When function length exceeds `config.module_health.function_length_error`, a `FunctionResult` with `status=FAILED`, `function=node.name`, `finding_type="function_length"` is emitted.
95
+
96
+ ### REQ-015: Function length advisory when exceeding warn threshold
97
+
98
+ When function length exceeds `config.module_health.function_length_warn` but not the error threshold, an advisory `FunctionResult` with `status=EXEMPT`, `finding_type="function_length"` is emitted.
99
+
100
+ ### REQ-016: Function length suggestions reference extraction patterns
101
+
102
+ The suggestion must mention: extracting comment-delimited sections, pulling nested loops/conditionals into helpers, and converting setup/teardown into context managers.
103
+
104
+ ---
105
+
106
+ ## Parameter Count Check
107
+
108
+ ### REQ-017: Parameter count excludes self and cls
109
+
110
+ `_check_parameter_count` counts non-receiver parameters (excluding `self`/`cls`) for each function. Both positional, keyword-only, `*args`, and `**kwargs` are counted.
111
+
112
+ ### REQ-018: Parameter count error when exceeding error threshold
113
+
114
+ When parameter count exceeds `config.module_health.parameter_count_error`, a `FunctionResult` with `status=FAILED`, `finding_type="parameter_count"` is emitted.
115
+
116
+ ### REQ-019: Parameter count advisory when exceeding warn threshold
117
+
118
+ When parameter count exceeds `config.module_health.parameter_count_warn` but not the error threshold, an advisory `FunctionResult` is emitted.
119
+
120
+ ### REQ-020: Parameter count suggestions reference Parameter Object pattern
121
+
122
+ The suggestion must mention grouping related parameters into a dataclass, TypedDict, or config object using the Parameter Object pattern.
123
+
124
+ ---
125
+
126
+ ## Class Method Count Check
127
+
128
+ ### REQ-021: Class method count includes all def nodes in class body
129
+
130
+ `_check_class_method_count` counts direct `FunctionDef` and `AsyncFunctionDef` children of each top-level `ClassDef` (not nested classes).
131
+
132
+ ### REQ-022: Class method count error when exceeding error threshold
133
+
134
+ When method count exceeds `config.module_health.class_method_count_error`, a `FunctionResult` with `status=FAILED`, `function=class_name`, `finding_type="class_method_count"` is emitted.
135
+
136
+ ### REQ-023: Class method count advisory when exceeding warn threshold
137
+
138
+ When method count exceeds `config.module_health.class_method_count_warn` but not the error threshold, an advisory `FunctionResult` is emitted.
139
+
140
+ ### REQ-024: Class method count suggestions reference SRP extraction
141
+
142
+ The suggestion must mention: extracting cohesive groups of methods sharing a prefix, methods accessing a subset of attributes, and methods that could be standalone functions.
143
+
144
+ ---
145
+
146
+ ## Split Suggestions
147
+
148
+ ### REQ-025: AST-based split point identification
149
+
150
+ A helper `_suggest_split_points` analyzes a file's AST and source to identify natural module boundaries:
151
+
152
+ - Top-level classes with their line span and method count.
153
+ - Groups of top-level functions sharing a common prefix (e.g., `parse_header`, `parse_body` -> `parse_*`).
154
+ - Banner comments (lines matching patterns like `# --- Section ---` or `# ====`) that suggest logical boundaries.
155
+
156
+ ### REQ-026: Split suggestions included in file-length findings
157
+
158
+ When file-length advisory or error findings are emitted, the suggestion field must include the output of `_suggest_split_points` formatted as a bullet list of concrete split candidates with line ranges.
159
+
160
+ ### REQ-027: Graceful fallback when no split points found
161
+
162
+ If `_suggest_split_points` identifies no clear boundaries, the file-length finding falls back to the generic refactoring suggestion without split points.
163
+
164
+ ---
165
+
166
+ ## Pipeline Integration
167
+
168
+ ### REQ-028: Module health checks run in Level 1 pipeline block
169
+
170
+ All four checks (`_check_file_length`, `_check_function_length`, `_check_parameter_count`, `_check_class_method_count`) are called within the Level 1 block of `run_pipeline`, after dead-code analysis. They are guarded by `config.module_health.enabled`.
171
+
172
+ ### REQ-029: Module health checks apply at all verification levels
173
+
174
+ Since the checks are part of Level 1 and Level 1 runs for all levels 1-6 (unless `--verify` skips it), module health checks run by default at every verification level.
175
+
176
+ ### REQ-030: Module health check results participate in early termination
177
+
178
+ If any module health check produces a FAILED result and `early_termination=True`, the pipeline stops at Level 1 (consistent with other Level 1 failures).
179
+
180
+ ---
181
+
182
+ ## CLI
183
+
184
+ ### REQ-031: --skip-module-health flag
185
+
186
+ The `serenecode check` command accepts a `--skip-module-health` boolean flag. When set, `config.module_health.enabled` is overridden to `False` via `dataclasses.replace` before the pipeline runs.
187
+
188
+ ### REQ-032: --fail-on-advisory applies to module health advisories
189
+
190
+ The existing `--fail-on-advisory` flag must trigger exit code 11 for any advisory, including module health warnings. The help text and exit message must not hardcode "dead-code."
191
+
192
+ ---
193
+
194
+ ## MCP Tool
195
+
196
+ ### REQ-033: serenecode_module_health tool returns file metrics
197
+
198
+ A new MCP tool `tool_module_health(path: str)` reads a single Python file and returns a dict containing:
199
+
200
+ - `file`: the file path.
201
+ - `metrics`: `line_count`, `function_count`, `class_count`, `largest_function` (name, lines, line), `max_parameters` (name, count, line), `largest_class` (name, method_count, line).
202
+ - `status`: per-metric status (`"ok"`, `"warning"`, `"error"`) derived from `ModuleHealthConfig` thresholds.
203
+ - `split_suggestions`: output of `_suggest_split_points`.
204
+
205
+ ### REQ-034: serenecode_module_health does not run the verification pipeline
206
+
207
+ The tool parses the AST and computes metrics directly, without calling `run_pipeline`. It does not require `--allow-code-execution`. It loads config via `_load_config` for threshold comparison.
208
+
209
+ ### REQ-035: serenecode_module_health registered in MCP server
210
+
211
+ The tool is registered in `build_server()` with a description emphasizing proactive use during editing to monitor module structure.
212
+
213
+ ---
214
+
215
+ ## Templates
216
+
217
+ ### REQ-036: Module health documented in all templates
218
+
219
+ Each template in `content.py` (default, strict, minimal) includes a "Module Health" subsection under Code Quality Standards documenting the four metrics, their warn/error thresholds, the advisory/error behavior, and the `--skip-module-health` flag.
220
+
221
+ ---
222
+
223
+ ## INT-001: Pipeline integration flow
224
+
225
+ Kind: call
226
+ Source: run_pipeline
227
+ Target: check_file_length
228
+
229
+ **Components:** `run_pipeline` (pipeline.py), `_check_file_length`, `_check_function_length`, `_check_parameter_count`, `_check_class_method_count`, `ModuleHealthConfig` (config.py)
230
+
231
+ **Flow:**
232
+ 1. `run_pipeline` enters Level 1 block.
233
+ 2. After structural checks + dead-code analysis, checks `config.module_health.enabled`.
234
+ 3. If enabled, calls all four `_check_*` functions, passing `source_files` and `config`.
235
+ 4. Each function iterates source files, skips test files, parses AST as needed, applies thresholds.
236
+ 5. Results (FAILED or EXEMPT advisory) are appended to `level_1_results`.
237
+ 6. Early termination triggers if any FAILED result exists.
238
+
239
+ **Contracts at boundary:** Each check function has icontract preconditions on inputs and postconditions ensuring returned list contains only valid `FunctionResult` objects.
240
+
241
+ ## INT-002: Advisory result propagation
242
+
243
+ Kind: call
244
+ Source: make_check_result
245
+ Target: ADVISORY_FINDING_TYPES
246
+
247
+ **Components:** `make_check_result` (models.py), `format_human` / `format_html` (reporter.py), `to_check_response` (schemas.py), `ADVISORY_FINDING_TYPES` (models.py)
248
+
249
+ **Flow:**
250
+ 1. Module health checks emit `FunctionResult` with `status=EXEMPT` and `finding_type in ADVISORY_FINDING_TYPES`.
251
+ 2. `make_check_result` counts these as `advisory_count` via set membership check.
252
+ 3. Reporter classifies them as advisory (visible, distinct from plain exempt) via same set.
253
+ 4. MCP schemas include them in wire findings via same set.
254
+ 5. CLI `--fail-on-advisory` triggers exit 11 when `advisory_count > 0`.
255
+
256
+ **Invariant:** `advisory_count` is always consistent across all three consumers because they share the single `ADVISORY_FINDING_TYPES` constant.
257
+
258
+ ## INT-003: CLI config override for --skip-module-health
259
+
260
+ Kind: call
261
+ Source: check
262
+ Target: run_pipeline
263
+
264
+ **Components:** `check` (cli.py), `SerenecodeConfig` (config.py), `ModuleHealthConfig` (config.py), `run_pipeline` (pipeline.py)
265
+
266
+ **Flow:**
267
+ 1. CLI parses `--skip-module-health` flag.
268
+ 2. If set, uses `dataclasses.replace` to create a new `SerenecodeConfig` with `module_health.enabled=False`.
269
+ 3. Modified config is passed to `run_pipeline`.
270
+ 4. Pipeline checks `config.module_health.enabled` and skips all four check functions.
271
+
272
+ **Postcondition:** When `--skip-module-health` is set, no `FunctionResult` with `finding_type in {"file_length", "function_length", "parameter_count", "class_method_count"}` appears in the output.
273
+
274
+ ## INT-004: MCP module_health tool standalone analysis
275
+
276
+ Kind: call
277
+ Source: tool_module_health
278
+ Target: _load_config
279
+
280
+ **Components:** `tool_module_health` (tools.py), `_load_config` (tools.py), `_suggest_split_points` (pipeline.py), `ModuleHealthConfig` (config.py)
281
+
282
+ **Flow:**
283
+ 1. Tool receives file path, reads source via `LocalFileReader`.
284
+ 2. Loads config via `_load_config` (cached, mtime-aware).
285
+ 3. Parses AST, computes metrics (line count, function sizes, parameter counts, class sizes).
286
+ 4. Compares each metric against `ModuleHealthConfig` thresholds to derive status.
287
+ 5. Calls `_suggest_split_points` on source + AST for split candidates.
288
+ 6. Returns structured dict with metrics, status, and suggestions.
289
+
290
+ **Postcondition:** Response always contains all metric fields even when file is empty or has no functions/classes (values are 0 / empty).
@@ -19,11 +19,11 @@ SereneCode checks stack from fast structural rules (Level 1) through types, cove
19
19
 
20
20
  ## Spec ergonomics
21
21
 
22
- - **Narrative vs traceability:** PRDs, `README` sections, and `*_SPEC.md` files are inputs. REQ/INT traceability and `serenecode check --spec` apply only to project-root **SPEC.md**, which must include a `**Source:** …` line (see SERENECODE.md). Run `serenecode doctor` to see whether SPEC.md and narrative-looking files were detected at the project root.
22
+ - **Narrative vs traceability:** PRDs, `README` sections, and `*_SPEC.md` files are inputs. REQ/INT traceability and `serenecode check --spec` apply only to project-root **SPEC.md**, which must include a `**Source:** …` line (see the Spec Traceability section in your project's `SERENECODE.md` from `serenecode init`, or the embedded templates in `src/serenecode/templates/content.py`). Run `serenecode doctor` to see whether SPEC.md and narrative-looking files were detected at the project root.
23
23
  - Use **one primary target per comma segment**; avoid stuffing unrelated names into a single `Target` line unless you intend AND semantics.
24
24
  - Align **dotted names** with how types appear in code (`from pkg import X as Y` is easier to reason about when `Target` uses the same simple name the implementation calls).
25
25
 
26
26
  ## Related reading
27
27
 
28
28
  - [SECURITY.md](SECURITY.md) — trust model for `--allow-code-execution` (required for Levels 3–6 as implemented today).
29
- - Project `SERENECODE.md` — conventions the structural checker enforces.
29
+ - Your project's `SERENECODE.md` (from `serenecode init`) — conventions the structural checker enforces; source templates live in `src/serenecode/templates/content.py`.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "serenecode"
3
- version = "0.4.0"
3
+ version = "0.5.0"
4
4
  description = "Verification framework for AI-generated Python — test coverage, property testing, and symbolic execution"
5
5
  requires-python = ">=3.10"
6
6
  license = "MIT"