atdd 0.4.6__tar.gz → 0.6.1__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 (211) hide show
  1. {atdd-0.4.6/src/atdd.egg-info → atdd-0.6.1}/PKG-INFO +1 -1
  2. {atdd-0.4.6 → atdd-0.6.1}/pyproject.toml +1 -1
  3. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/inventory.py +91 -3
  4. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/registry.py +114 -5
  5. atdd-0.6.1/src/atdd/coach/schemas/config.schema.json +128 -0
  6. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/templates/ATDD.md +1 -1
  7. atdd-0.6.1/src/atdd/coach/utils/config.py +131 -0
  8. atdd-0.6.1/src/atdd/coach/utils/coverage_phase.py +97 -0
  9. atdd-0.6.1/src/atdd/coach/utils/train_spec_phase.py +97 -0
  10. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/validators/shared_fixtures.py +222 -1
  11. atdd-0.6.1/src/atdd/coach/validators/test_train_registry.py +189 -0
  12. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/backend.convention.yaml +1 -1
  13. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/boundaries.convention.yaml +9 -9
  14. atdd-0.6.1/src/atdd/coder/conventions/coverage.convention.yaml +85 -0
  15. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/presentation.convention.yaml +8 -8
  16. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/train.convention.yaml +15 -14
  17. atdd-0.6.1/src/atdd/coder/validators/conftest.py +5 -0
  18. atdd-0.6.1/src/atdd/coder/validators/test_hierarchy_coverage.py +361 -0
  19. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_presentation_convention.py +11 -11
  20. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_station_master_pattern.py +16 -14
  21. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_train_infrastructure.py +258 -16
  22. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_wagon_boundaries.py +2 -2
  23. atdd-0.6.1/src/atdd/planner/conventions/coverage.convention.yaml +95 -0
  24. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/schemas/train.schema.json +125 -2
  25. atdd-0.6.1/src/atdd/planner/validators/test_hierarchy_coverage.py +433 -0
  26. atdd-0.6.1/src/atdd/planner/validators/test_train_validation.py +1181 -0
  27. atdd-0.6.1/src/atdd/tester/conventions/coverage.convention.yaml +114 -0
  28. atdd-0.6.1/src/atdd/tester/validators/test_hierarchy_coverage.py +604 -0
  29. atdd-0.6.1/src/atdd/tester/validators/test_train_backend_e2e.py +371 -0
  30. atdd-0.6.1/src/atdd/tester/validators/test_train_frontend_e2e.py +292 -0
  31. atdd-0.6.1/src/atdd/tester/validators/test_train_frontend_python.py +282 -0
  32. {atdd-0.4.6 → atdd-0.6.1/src/atdd.egg-info}/PKG-INFO +1 -1
  33. {atdd-0.4.6 → atdd-0.6.1}/src/atdd.egg-info/SOURCES.txt +14 -0
  34. atdd-0.4.6/src/atdd/coach/schemas/config.schema.json +0 -65
  35. atdd-0.4.6/src/atdd/planner/validators/test_train_validation.py +0 -516
  36. {atdd-0.4.6 → atdd-0.6.1}/LICENSE +0 -0
  37. {atdd-0.4.6 → atdd-0.6.1}/README.md +0 -0
  38. {atdd-0.4.6 → atdd-0.6.1}/setup.cfg +0 -0
  39. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/__init__.py +0 -0
  40. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/__main__.py +0 -0
  41. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/cli.py +0 -0
  42. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/__init__.py +0 -0
  43. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/__init__.py +0 -0
  44. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/add_persistence_metadata.py +0 -0
  45. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/analyze_migrations.py +0 -0
  46. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/consumers.py +0 -0
  47. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/gate.py +0 -0
  48. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/infer_governance_status.py +0 -0
  49. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/initializer.py +0 -0
  50. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/interface.py +0 -0
  51. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/migration.py +0 -0
  52. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/session.py +0 -0
  53. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/sync.py +0 -0
  54. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/test_interface.py +0 -0
  55. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/test_runner.py +0 -0
  56. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/tests/__init__.py +0 -0
  57. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/tests/test_telemetry_array_validation.py +0 -0
  58. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/commands/traceability.py +0 -0
  59. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/conventions/session.convention.yaml +0 -0
  60. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/overlays/__init__.py +0 -0
  61. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/overlays/claude.md +0 -0
  62. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/schemas/manifest.schema.json +0 -0
  63. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/templates/SESSION-TEMPLATE.md +0 -0
  64. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/utils/__init__.py +0 -0
  65. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/utils/graph/__init__.py +0 -0
  66. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/utils/graph/urn.py +0 -0
  67. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/utils/repo.py +0 -0
  68. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/validators/__init__.py +0 -0
  69. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/validators/test_enrich_wagon_registry.py +0 -0
  70. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/validators/test_registry.py +0 -0
  71. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/validators/test_release_versioning.py +0 -0
  72. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/validators/test_session_validation.py +0 -0
  73. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/validators/test_traceability.py +0 -0
  74. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/validators/test_update_feature_paths.py +0 -0
  75. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coach/validators/test_validate_contract_consumers.py +0 -0
  76. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/__init__.py +0 -0
  77. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/adapter.recipe.yaml +0 -0
  78. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/commons.convention.yaml +0 -0
  79. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/complexity.recipe.yaml +0 -0
  80. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/component-naming.convention.yaml +0 -0
  81. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/design.convention.yaml +0 -0
  82. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/design.recipe.yaml +0 -0
  83. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/dto.convention.yaml +0 -0
  84. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/frontend.convention.yaml +0 -0
  85. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/green.convention.yaml +0 -0
  86. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/refactor.convention.yaml +0 -0
  87. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/technology.convention.yaml +0 -0
  88. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/tests/__init__.py +0 -0
  89. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/tests/test_adapter_recipe.py +0 -0
  90. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/tests/test_complexity_recipe.py +0 -0
  91. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/tests/test_component_taxonomy.py +0 -0
  92. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/tests/test_component_urn_naming.py +0 -0
  93. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/tests/test_thinness_recipe.py +0 -0
  94. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/thinness.recipe.yaml +0 -0
  95. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/conventions/verification.protocol.yaml +0 -0
  96. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/schemas/design_system.schema.json +0 -0
  97. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/__init__.py +0 -0
  98. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_commons_structure.py +0 -0
  99. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_complexity.py +0 -0
  100. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_cross_language_consistency.py +0 -0
  101. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_design_system_compliance.py +0 -0
  102. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_dto_testing_patterns.py +0 -0
  103. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_green_cross_stack_layers.py +0 -0
  104. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_green_layer_dependencies.py +0 -0
  105. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_green_python_layer_structure.py +0 -0
  106. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_green_supabase_layer_structure.py +0 -0
  107. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_import_boundaries.py +0 -0
  108. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_init_file_urns.py +0 -0
  109. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_preact_layer_boundaries.py +0 -0
  110. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_python_architecture.py +0 -0
  111. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_quality_metrics.py +0 -0
  112. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_train_urns.py +0 -0
  113. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_typescript_architecture.py +0 -0
  114. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/coder/validators/test_usecase_structure.py +0 -0
  115. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/conftest.py +0 -0
  116. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/__init__.py +0 -0
  117. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/conventions/acceptance.convention.yaml +0 -0
  118. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/conventions/appendix.convention.yaml +0 -0
  119. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/conventions/artifact-naming.convention.yaml +0 -0
  120. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/conventions/component.convention.yaml +0 -0
  121. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/conventions/criteria.convention.yaml +0 -0
  122. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/conventions/feature.convention.yaml +0 -0
  123. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/conventions/interface.convention.yaml +0 -0
  124. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/conventions/steps.convention.yaml +0 -0
  125. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/conventions/train.convention.yaml +0 -0
  126. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/conventions/wagon.convention.yaml +0 -0
  127. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/conventions/wmbt.convention.yaml +0 -0
  128. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/schemas/acceptance.schema.json +0 -0
  129. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/schemas/appendix.schema.json +0 -0
  130. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/schemas/component.schema.json +0 -0
  131. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/schemas/feature.schema.json +0 -0
  132. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/schemas/wagon.schema.json +0 -0
  133. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/schemas/wmbt.schema.json +0 -0
  134. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/validators/__init__.py +0 -0
  135. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/validators/conftest.py +0 -0
  136. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/validators/test_draft_wagon_registry.py +0 -0
  137. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/validators/test_plan_cross_refs.py +0 -0
  138. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/validators/test_plan_uniqueness.py +0 -0
  139. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/validators/test_plan_urn_resolution.py +0 -0
  140. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/validators/test_plan_wagons.py +0 -0
  141. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/validators/test_wagon_urn_chain.py +0 -0
  142. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/validators/test_wmbt_consistency.py +0 -0
  143. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/planner/validators/test_wmbt_vocabulary.py +0 -0
  144. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/__init__.py +0 -0
  145. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/conventions/artifact.convention.yaml +0 -0
  146. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/conventions/contract.convention.yaml +0 -0
  147. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/conventions/filename.convention.yaml +0 -0
  148. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/conventions/migration.convention.yaml +0 -0
  149. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/conventions/red.convention.yaml +0 -0
  150. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/conventions/routing.convention.yaml +0 -0
  151. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/conventions/security.convention.yaml +0 -0
  152. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/conventions/telemetry.convention.yaml +0 -0
  153. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/a11y.tmpl.json +0 -0
  154. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/artifact.schema.json +0 -0
  155. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/contract.schema.json +0 -0
  156. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/contract.tmpl.json +0 -0
  157. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/db.tmpl.json +0 -0
  158. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/e2e.tmpl.json +0 -0
  159. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/edge_function.tmpl.json +0 -0
  160. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/event.tmpl.json +0 -0
  161. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/http.tmpl.json +0 -0
  162. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/job.tmpl.json +0 -0
  163. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/load.tmpl.json +0 -0
  164. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/metric.tmpl.json +0 -0
  165. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/pack.schema.json +0 -0
  166. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/realtime.tmpl.json +0 -0
  167. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/rls.tmpl.json +0 -0
  168. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/script.tmpl.json +0 -0
  169. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/sec.tmpl.json +0 -0
  170. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/storage.tmpl.json +0 -0
  171. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/telemetry.schema.json +0 -0
  172. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/telemetry_tracking_manifest.schema.json +0 -0
  173. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/test_filename.schema.json +0 -0
  174. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/test_intent.schema.json +0 -0
  175. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/unit.tmpl.json +0 -0
  176. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/visual.tmpl.json +0 -0
  177. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/schemas/ws.tmpl.json +0 -0
  178. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/utils/__init__.py +0 -0
  179. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/utils/filename.py +0 -0
  180. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/__init__.py +0 -0
  181. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/cleanup_duplicate_headers.py +0 -0
  182. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/cleanup_duplicate_headers_v2.py +0 -0
  183. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/conftest.py +0 -0
  184. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/coverage_gap_report.py +0 -0
  185. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/fix_dual_ac_references.py +0 -0
  186. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/remove_duplicate_lines.py +0 -0
  187. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_acceptance_urn_filename_mapping.py +0 -0
  188. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_acceptance_urn_separator.py +0 -0
  189. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_artifact_naming_category.py +0 -0
  190. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_contract_schema_compliance.py +0 -0
  191. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_contract_security.py +0 -0
  192. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_contracts_structure.py +0 -0
  193. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_coverage_adequacy.py +0 -0
  194. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_dual_ac_reference.py +0 -0
  195. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_fixture_validity.py +0 -0
  196. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_isolation.py +0 -0
  197. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_migration_coverage.py +0 -0
  198. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_migration_criteria.py +0 -0
  199. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_migration_generation.py +0 -0
  200. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_python_test_naming.py +0 -0
  201. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_red_layer_validation.py +0 -0
  202. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_red_python_layer_structure.py +0 -0
  203. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_red_supabase_layer_structure.py +0 -0
  204. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_telemetry_structure.py +0 -0
  205. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_typescript_test_naming.py +0 -0
  206. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/tester/validators/test_typescript_test_structure.py +0 -0
  207. {atdd-0.4.6 → atdd-0.6.1}/src/atdd/version_check.py +0 -0
  208. {atdd-0.4.6 → atdd-0.6.1}/src/atdd.egg-info/dependency_links.txt +0 -0
  209. {atdd-0.4.6 → atdd-0.6.1}/src/atdd.egg-info/entry_points.txt +0 -0
  210. {atdd-0.4.6 → atdd-0.6.1}/src/atdd.egg-info/requires.txt +0 -0
  211. {atdd-0.4.6 → atdd-0.6.1}/src/atdd.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: atdd
3
- Version: 0.4.6
3
+ Version: 0.6.1
4
4
  Summary: ATDD Platform - Acceptance Test Driven Development toolkit
5
5
  License: MIT
6
6
  Requires-Python: >=3.10
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "atdd"
7
- version = "0.4.6"
7
+ version = "0.6.1"
8
8
  description = "ATDD Platform - Acceptance Test Driven Development toolkit"
9
9
  requires-python = ">=3.10"
10
10
  readme = "README.md"
@@ -75,11 +75,32 @@ class RepositoryInventory:
75
75
  }
76
76
 
77
77
  def scan_trains(self) -> Dict[str, Any]:
78
- """Scan plan/ for train manifests (aggregations of wagons)."""
78
+ """
79
+ Scan plan/ for train manifests (aggregations of wagons).
80
+
81
+ Train First-Class Spec v0.6 Section 14: Gap Reporting
82
+ Reports missing test/code for each platform (backend/frontend/frontend_python).
83
+ """
79
84
  plan_dir = self.repo_root / "plan"
80
85
 
81
86
  if not plan_dir.exists():
82
- return {"total": 0, "trains": []}
87
+ return {
88
+ "total": 0,
89
+ "trains": [],
90
+ "by_theme": {},
91
+ "train_ids": [],
92
+ "detail_files": 0,
93
+ "missing_test_backend": [],
94
+ "missing_test_frontend": [],
95
+ "missing_test_frontend_python": [],
96
+ "missing_code_backend": [],
97
+ "missing_code_frontend": [],
98
+ "missing_code_frontend_python": [],
99
+ "gaps": {
100
+ "test": {"backend": 0, "frontend": 0, "frontend_python": 0},
101
+ "code": {"backend": 0, "frontend": 0, "frontend_python": 0}
102
+ }
103
+ }
83
104
 
84
105
  # Load trains registry
85
106
  trains_file = plan_dir / "_trains.yaml"
@@ -103,6 +124,14 @@ class RepositoryInventory:
103
124
  by_theme = defaultdict(int)
104
125
  train_ids = []
105
126
 
127
+ # Gap tracking (Section 14)
128
+ missing_test_backend = []
129
+ missing_test_frontend = []
130
+ missing_test_frontend_python = []
131
+ missing_code_backend = []
132
+ missing_code_frontend = []
133
+ missing_code_frontend_python = []
134
+
106
135
  for train in all_trains:
107
136
  train_id = train.get("train_id", "unknown")
108
137
  train_ids.append(train_id)
@@ -118,6 +147,46 @@ class RepositoryInventory:
118
147
  theme = theme_map.get(theme_digit, "unknown")
119
148
  by_theme[theme] += 1
120
149
 
150
+ # Gap analysis
151
+ expectations = train.get("expectations", {})
152
+ test_fields = train.get("test", {})
153
+ code_fields = train.get("code", {})
154
+
155
+ # Normalize test/code to dict form
156
+ if isinstance(test_fields, str):
157
+ test_fields = {"backend": [test_fields]}
158
+ elif isinstance(test_fields, list):
159
+ test_fields = {"backend": test_fields}
160
+
161
+ if isinstance(code_fields, str):
162
+ code_fields = {"backend": [code_fields]}
163
+ elif isinstance(code_fields, list):
164
+ code_fields = {"backend": code_fields}
165
+
166
+ # Check backend gaps (default expectation is True for backend)
167
+ expects_backend = expectations.get("backend", True)
168
+ if expects_backend:
169
+ if not test_fields.get("backend"):
170
+ missing_test_backend.append(train_id)
171
+ if not code_fields.get("backend"):
172
+ missing_code_backend.append(train_id)
173
+
174
+ # Check frontend gaps
175
+ expects_frontend = expectations.get("frontend", False)
176
+ if expects_frontend:
177
+ if not test_fields.get("frontend"):
178
+ missing_test_frontend.append(train_id)
179
+ if not code_fields.get("frontend"):
180
+ missing_code_frontend.append(train_id)
181
+
182
+ # Check frontend_python gaps
183
+ expects_frontend_python = expectations.get("frontend_python", False)
184
+ if expects_frontend_python:
185
+ if not test_fields.get("frontend_python"):
186
+ missing_test_frontend_python.append(train_id)
187
+ if not code_fields.get("frontend_python"):
188
+ missing_code_frontend_python.append(train_id)
189
+
121
190
  # Find train detail files
122
191
  train_detail_files = list((plan_dir / "_trains").glob("*.yaml")) if (plan_dir / "_trains").exists() else []
123
192
 
@@ -125,7 +194,26 @@ class RepositoryInventory:
125
194
  "total": len(all_trains),
126
195
  "by_theme": dict(by_theme),
127
196
  "train_ids": train_ids,
128
- "detail_files": len(train_detail_files)
197
+ "detail_files": len(train_detail_files),
198
+ # Gap reporting (Section 14)
199
+ "missing_test_backend": missing_test_backend,
200
+ "missing_test_frontend": missing_test_frontend,
201
+ "missing_test_frontend_python": missing_test_frontend_python,
202
+ "missing_code_backend": missing_code_backend,
203
+ "missing_code_frontend": missing_code_frontend,
204
+ "missing_code_frontend_python": missing_code_frontend_python,
205
+ "gaps": {
206
+ "test": {
207
+ "backend": len(missing_test_backend),
208
+ "frontend": len(missing_test_frontend),
209
+ "frontend_python": len(missing_test_frontend_python)
210
+ },
211
+ "code": {
212
+ "backend": len(missing_code_backend),
213
+ "frontend": len(missing_code_frontend),
214
+ "frontend_python": len(missing_code_frontend_python)
215
+ }
216
+ }
129
217
  }
130
218
 
131
219
  def scan_wagons(self) -> Dict[str, Any]:
@@ -910,6 +910,44 @@ class RegistryBuilder:
910
910
  mode = "check" if preview_only else "interactive"
911
911
  return self.update_telemetry_registry(mode)
912
912
 
913
+ def _normalize_test_code_field(self, field_value: Any) -> Dict[str, List[str]]:
914
+ """
915
+ Normalize test/code field to canonical structure.
916
+
917
+ Train First-Class Spec v0.6 Section 5: Test/Code Field Typing Normalization
918
+ - string -> {"backend": [string]}
919
+ - list -> {"backend": list}
920
+ - dict -> normalize each sub-field to list
921
+ """
922
+ if field_value is None:
923
+ return {}
924
+
925
+ if isinstance(field_value, str):
926
+ return {"backend": [field_value]}
927
+ elif isinstance(field_value, list):
928
+ return {"backend": field_value}
929
+ elif isinstance(field_value, dict):
930
+ result = {}
931
+ for key in ["backend", "frontend", "frontend_python"]:
932
+ if key in field_value:
933
+ val = field_value[key]
934
+ result[key] = [val] if isinstance(val, str) else (val or [])
935
+ return result
936
+ return {}
937
+
938
+ def _extract_wagons_from_participants(self, participants: List[str]) -> List[str]:
939
+ """
940
+ Extract wagon names from participants list.
941
+
942
+ Train First-Class Spec v0.6 Section 4: Participants is Canonical Wagon Source
943
+ """
944
+ wagons = []
945
+ for participant in participants:
946
+ if isinstance(participant, str) and participant.startswith("wagon:"):
947
+ wagon_name = participant.replace("wagon:", "")
948
+ wagons.append(wagon_name)
949
+ return wagons
950
+
913
951
  def build_trains(self, mode: str = "interactive") -> Dict[str, Any]:
914
952
  """
915
953
  Build trains registry from train manifest files.
@@ -920,12 +958,19 @@ class RegistryBuilder:
920
958
  - XX = category within theme
921
959
  - name = train slug
922
960
 
961
+ Train First-Class Spec v0.6 Normalization:
962
+ - Section 1: Normalize file→path (deprecation)
963
+ - Section 4: Extract wagons from participants
964
+ - Section 5: Normalize test/code fields to {backend/frontend/frontend_python: []}
965
+
923
966
  Args:
924
967
  mode: "interactive" (prompt), "apply" (no prompt), or "check" (verify only)
925
968
 
926
969
  Returns:
927
970
  Statistics about the update (includes has_changes flag for check mode)
928
971
  """
972
+ import warnings
973
+
929
974
  print("\n📊 Analyzing trains registry from manifest files...")
930
975
 
931
976
  # Set up paths
@@ -947,6 +992,7 @@ class RegistryBuilder:
947
992
  "new": 0,
948
993
  "errors": 0,
949
994
  "preserved_drafts": 0,
995
+ "file_to_path_migrations": 0,
950
996
  "changes": []
951
997
  }
952
998
 
@@ -987,31 +1033,92 @@ class RegistryBuilder:
987
1033
  # Try to infer from filename (e.g., 01-01-setup.yaml -> 01-01-setup)
988
1034
  train_id = manifest_path.stem
989
1035
 
990
- # Parse theme from train_id (first 2 digits)
1036
+ # Parse theme from train_id (first digit maps to theme name)
991
1037
  theme = ""
992
- if len(train_id) >= 2 and train_id[:2].isdigit():
993
- theme = train_id[:2]
1038
+ theme_map = {
1039
+ "0": "commons", "1": "mechanic", "2": "scenario", "3": "match",
1040
+ "4": "sensory", "5": "player", "6": "league", "7": "audience",
1041
+ "8": "monetization", "9": "partnership"
1042
+ }
1043
+ if train_id and train_id[0].isdigit():
1044
+ theme = theme_map.get(train_id[0], "")
994
1045
 
995
1046
  # Build train entry
996
1047
  rel_manifest = str(manifest_path.relative_to(self.repo_root))
997
1048
 
1049
+ # Section 1: Normalize file→path
1050
+ path_value = manifest.get("path")
1051
+ file_value = manifest.get("file")
1052
+ if file_value and not path_value:
1053
+ # Migrate file to path
1054
+ path_value = file_value
1055
+ stats["file_to_path_migrations"] += 1
1056
+ warnings.warn(
1057
+ f"Train {train_id}: 'file' field is deprecated, migrating to 'path'",
1058
+ DeprecationWarning,
1059
+ stacklevel=2
1060
+ )
1061
+
1062
+ # Section 4: Extract wagons from participants
1063
+ participants = manifest.get("participants", [])
1064
+ wagons = self._extract_wagons_from_participants(participants)
1065
+
1066
+ # Also include explicitly listed wagons
1067
+ explicit_wagons = manifest.get("wagons", [])
1068
+ if explicit_wagons:
1069
+ # Validate subset relationship
1070
+ explicit_set = set(explicit_wagons)
1071
+ participant_set = set(wagons)
1072
+ if not explicit_set.issubset(participant_set) and participant_set:
1073
+ extra = explicit_set - participant_set
1074
+ warnings.warn(
1075
+ f"Train {train_id}: registry wagons {extra} not in YAML participants",
1076
+ UserWarning,
1077
+ stacklevel=2
1078
+ )
1079
+ wagons = explicit_wagons # Use explicit if provided
1080
+
1081
+ # Section 5: Normalize test/code fields
1082
+ test_normalized = self._normalize_test_code_field(manifest.get("test"))
1083
+ code_normalized = self._normalize_test_code_field(manifest.get("code"))
1084
+
998
1085
  entry = {
999
1086
  "train_id": train_id,
1000
1087
  "theme": theme,
1001
1088
  "title": manifest.get("title", manifest.get("description", "")),
1002
1089
  "description": manifest.get("description", ""),
1003
- "wagons": manifest.get("wagons", []),
1090
+ "wagons": wagons,
1004
1091
  "status": manifest.get("status", "planned"),
1005
1092
  "manifest": rel_manifest
1006
1093
  }
1007
1094
 
1095
+ # Add path if present
1096
+ if path_value:
1097
+ entry["path"] = path_value
1098
+
1099
+ # Add primary_wagon if present
1100
+ primary_wagon = manifest.get("primary_wagon")
1101
+ if primary_wagon:
1102
+ entry["primary_wagon"] = primary_wagon
1103
+
1104
+ # Add normalized test/code if present
1105
+ if test_normalized:
1106
+ entry["test"] = test_normalized
1107
+ if code_normalized:
1108
+ entry["code"] = code_normalized
1109
+
1110
+ # Add expectations if present
1111
+ expectations = manifest.get("expectations")
1112
+ if expectations:
1113
+ entry["expectations"] = expectations
1114
+
1008
1115
  # Check if updating or new
1009
1116
  if train_id in existing_trains:
1010
1117
  stats["updated"] += 1
1011
1118
  # Check for field changes
1012
1119
  old = existing_trains[train_id]
1013
1120
  changed_fields = []
1014
- for field in ["title", "description", "wagons", "status", "theme"]:
1121
+ for field in ["title", "description", "wagons", "status", "theme", "path", "test", "code", "expectations"]:
1015
1122
  if old.get(field) != entry.get(field):
1016
1123
  changed_fields.append(field)
1017
1124
  if changed_fields:
@@ -1052,6 +1159,8 @@ class RegistryBuilder:
1052
1159
  print(f" • {stats['updated']} trains will be updated")
1053
1160
  print(f" • {stats['new']} new trains will be added")
1054
1161
  print(f" • {stats['preserved_drafts']} draft trains will be preserved")
1162
+ if stats["file_to_path_migrations"] > 0:
1163
+ print(f" ⚠️ {stats['file_to_path_migrations']} file→path migrations (deprecation)")
1055
1164
  if stats["errors"] > 0:
1056
1165
  print(f" ⚠️ {stats['errors']} errors encountered")
1057
1166
 
@@ -0,0 +1,128 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://atdd.dev/schemas/config.schema.json",
4
+ "title": "ATDD Config",
5
+ "description": "Schema for .atdd/config.yaml configuration file",
6
+ "type": "object",
7
+ "properties": {
8
+ "version": {
9
+ "type": "string",
10
+ "description": "Configuration schema version",
11
+ "pattern": "^[0-9]+\\.[0-9]+$",
12
+ "examples": ["1.0"]
13
+ },
14
+ "release": {
15
+ "type": "object",
16
+ "description": "Release/versioning settings",
17
+ "properties": {
18
+ "version_file": {
19
+ "type": "string",
20
+ "description": "Path to version file (relative to repo root)",
21
+ "examples": ["pyproject.toml", "package.json", "VERSION"]
22
+ },
23
+ "tag_prefix": {
24
+ "type": "string",
25
+ "description": "Prefix for git tags",
26
+ "default": "v",
27
+ "examples": ["v", ""]
28
+ }
29
+ },
30
+ "required": ["version_file"],
31
+ "additionalProperties": false
32
+ },
33
+ "sync": {
34
+ "type": "object",
35
+ "description": "Agent config file sync settings",
36
+ "properties": {
37
+ "agents": {
38
+ "type": "array",
39
+ "description": "List of agents to sync ATDD rules to",
40
+ "items": {
41
+ "type": "string",
42
+ "enum": ["claude", "codex", "gemini", "qwen"]
43
+ },
44
+ "uniqueItems": true,
45
+ "default": ["claude"]
46
+ }
47
+ },
48
+ "additionalProperties": false
49
+ },
50
+ "toolkit": {
51
+ "type": "object",
52
+ "description": "ATDD toolkit metadata",
53
+ "properties": {
54
+ "last_version": {
55
+ "type": "string",
56
+ "description": "Last installed ATDD toolkit version"
57
+ }
58
+ },
59
+ "required": ["last_version"],
60
+ "additionalProperties": false
61
+ },
62
+ "coverage": {
63
+ "type": "object",
64
+ "description": "Hierarchy coverage validation settings (ATDD Hierarchy Coverage Spec v0.1)",
65
+ "properties": {
66
+ "exceptions": {
67
+ "type": "object",
68
+ "description": "Allow-lists for coverage exceptions",
69
+ "properties": {
70
+ "wagons_not_in_train": {
71
+ "type": "array",
72
+ "items": {"type": "string"},
73
+ "description": "Wagon slugs allowed without train coverage"
74
+ },
75
+ "features_orphaned": {
76
+ "type": "array",
77
+ "items": {"type": "string"},
78
+ "description": "Feature URNs allowed without wagon manifest reference"
79
+ },
80
+ "wmbts_without_acceptance": {
81
+ "type": "array",
82
+ "items": {"type": "string"},
83
+ "description": "WMBT URNs allowed without acceptance criteria"
84
+ },
85
+ "acceptance_without_tests": {
86
+ "type": "array",
87
+ "items": {"type": "string"},
88
+ "description": "Acceptance URNs allowed without test coverage"
89
+ },
90
+ "contracts_unreferenced": {
91
+ "type": "array",
92
+ "items": {"type": "string"},
93
+ "description": "Contract URNs allowed without produce/consume"
94
+ },
95
+ "telemetry_unreferenced": {
96
+ "type": "array",
97
+ "items": {"type": "string"},
98
+ "description": "Telemetry URNs allowed without references"
99
+ },
100
+ "features_without_implementation": {
101
+ "type": "array",
102
+ "items": {"type": "string"},
103
+ "description": "Feature URNs allowed without code implementation"
104
+ }
105
+ },
106
+ "additionalProperties": false
107
+ },
108
+ "thresholds": {
109
+ "type": "object",
110
+ "description": "Coverage threshold settings",
111
+ "properties": {
112
+ "min_acceptance_coverage": {
113
+ "type": "number",
114
+ "minimum": 0,
115
+ "maximum": 100,
116
+ "default": 80,
117
+ "description": "Minimum percentage of acceptances that must have tests"
118
+ }
119
+ },
120
+ "additionalProperties": false
121
+ }
122
+ },
123
+ "additionalProperties": false
124
+ }
125
+ },
126
+ "required": ["version", "release"],
127
+ "additionalProperties": false
128
+ }
@@ -71,7 +71,7 @@ code:
71
71
  # Dev Servers
72
72
  dev_servers:
73
73
  backend:
74
- command: "cd python && python3 game.py"
74
+ command: "cd python && python3 app.py"
75
75
  url: "http://127.0.0.1:8000"
76
76
  swagger: "http://127.0.0.1:8000/docs"
77
77
  frontend:
@@ -0,0 +1,131 @@
1
+ """
2
+ ATDD Configuration Loader.
3
+
4
+ Loads configuration from .atdd/config.yaml for train validation and enforcement.
5
+ """
6
+
7
+ import yaml
8
+ from pathlib import Path
9
+ from typing import Dict, Any, Optional
10
+
11
+
12
+ def load_atdd_config(repo_root: Path) -> Dict[str, Any]:
13
+ """
14
+ Load .atdd/config.yaml configuration file.
15
+
16
+ The config file controls:
17
+ - FastAPI template enforcement (Section 11)
18
+ - Train validation behavior
19
+ - Custom path conventions
20
+
21
+ Args:
22
+ repo_root: Repository root path
23
+
24
+ Returns:
25
+ Parsed configuration dict, or empty dict if file doesn't exist
26
+
27
+ Example config:
28
+ trains:
29
+ enforce_fastapi_template: true
30
+ backend_runner_paths:
31
+ - python/trains/runner.py
32
+ - python/trains/{train_id}/runner.py
33
+ frontend_allowed_roots:
34
+ - web/src/
35
+ - web/components/
36
+ """
37
+ config_path = repo_root / ".atdd" / "config.yaml"
38
+
39
+ if not config_path.exists():
40
+ return {}
41
+
42
+ try:
43
+ with open(config_path) as f:
44
+ config = yaml.safe_load(f)
45
+ return config if config else {}
46
+ except Exception:
47
+ return {}
48
+
49
+
50
+ def get_train_config(repo_root: Path) -> Dict[str, Any]:
51
+ """
52
+ Get train-specific configuration.
53
+
54
+ Args:
55
+ repo_root: Repository root path
56
+
57
+ Returns:
58
+ Train configuration dict with defaults applied
59
+ """
60
+ config = load_atdd_config(repo_root)
61
+ train_config = config.get("trains", {})
62
+
63
+ # Apply defaults
64
+ defaults = {
65
+ "enforce_fastapi_template": False,
66
+ "backend_runner_paths": [
67
+ "python/trains/runner.py",
68
+ "python/trains/{train_id}/runner.py"
69
+ ],
70
+ "frontend_allowed_roots": [
71
+ "web/src/",
72
+ "web/components/",
73
+ "web/pages/"
74
+ ],
75
+ "frontend_python_paths": [
76
+ "python/streamlit/",
77
+ "python/apps/"
78
+ ],
79
+ "e2e_backend_pattern": "e2e/{theme}/test_{train_id}*.py",
80
+ "e2e_frontend_pattern": "web/e2e/{train_id}/*.spec.ts"
81
+ }
82
+
83
+ # Merge with defaults
84
+ for key, default_value in defaults.items():
85
+ if key not in train_config:
86
+ train_config[key] = default_value
87
+
88
+ return train_config
89
+
90
+
91
+ def get_validation_config(repo_root: Path) -> Dict[str, Any]:
92
+ """
93
+ Get validation-specific configuration.
94
+
95
+ Args:
96
+ repo_root: Repository root path
97
+
98
+ Returns:
99
+ Validation configuration with defaults
100
+ """
101
+ config = load_atdd_config(repo_root)
102
+ validation_config = config.get("validation", {})
103
+
104
+ defaults = {
105
+ "strict_mode": False,
106
+ "warn_on_missing_tests": True,
107
+ "warn_on_missing_code": True,
108
+ "require_primary_wagon": False
109
+ }
110
+
111
+ for key, default_value in defaults.items():
112
+ if key not in validation_config:
113
+ validation_config[key] = default_value
114
+
115
+ return validation_config
116
+
117
+
118
+ def is_feature_enabled(repo_root: Path, feature: str) -> bool:
119
+ """
120
+ Check if a specific feature is enabled in config.
121
+
122
+ Args:
123
+ repo_root: Repository root path
124
+ feature: Feature name to check
125
+
126
+ Returns:
127
+ True if feature is enabled, False otherwise
128
+ """
129
+ config = load_atdd_config(repo_root)
130
+ features = config.get("features", {})
131
+ return features.get(feature, False)