atdd 0.1.0__py3-none-any.whl

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 (183) hide show
  1. atdd/__init__.py +0 -0
  2. atdd/cli.py +404 -0
  3. atdd/coach/__init__.py +0 -0
  4. atdd/coach/commands/__init__.py +0 -0
  5. atdd/coach/commands/add_persistence_metadata.py +215 -0
  6. atdd/coach/commands/analyze_migrations.py +188 -0
  7. atdd/coach/commands/consumers.py +720 -0
  8. atdd/coach/commands/infer_governance_status.py +149 -0
  9. atdd/coach/commands/initializer.py +177 -0
  10. atdd/coach/commands/interface.py +1078 -0
  11. atdd/coach/commands/inventory.py +565 -0
  12. atdd/coach/commands/migration.py +240 -0
  13. atdd/coach/commands/registry.py +1560 -0
  14. atdd/coach/commands/session.py +430 -0
  15. atdd/coach/commands/sync.py +405 -0
  16. atdd/coach/commands/test_interface.py +399 -0
  17. atdd/coach/commands/test_runner.py +141 -0
  18. atdd/coach/commands/tests/__init__.py +1 -0
  19. atdd/coach/commands/tests/test_telemetry_array_validation.py +235 -0
  20. atdd/coach/commands/traceability.py +4264 -0
  21. atdd/coach/conventions/session.convention.yaml +754 -0
  22. atdd/coach/overlays/__init__.py +2 -0
  23. atdd/coach/overlays/claude.md +2 -0
  24. atdd/coach/schemas/config.schema.json +34 -0
  25. atdd/coach/schemas/manifest.schema.json +101 -0
  26. atdd/coach/templates/ATDD.md +282 -0
  27. atdd/coach/templates/SESSION-TEMPLATE.md +327 -0
  28. atdd/coach/utils/__init__.py +0 -0
  29. atdd/coach/utils/graph/__init__.py +0 -0
  30. atdd/coach/utils/graph/urn.py +875 -0
  31. atdd/coach/validators/__init__.py +0 -0
  32. atdd/coach/validators/shared_fixtures.py +365 -0
  33. atdd/coach/validators/test_enrich_wagon_registry.py +167 -0
  34. atdd/coach/validators/test_registry.py +575 -0
  35. atdd/coach/validators/test_session_validation.py +1183 -0
  36. atdd/coach/validators/test_traceability.py +448 -0
  37. atdd/coach/validators/test_update_feature_paths.py +108 -0
  38. atdd/coach/validators/test_validate_contract_consumers.py +297 -0
  39. atdd/coder/__init__.py +1 -0
  40. atdd/coder/conventions/adapter.recipe.yaml +88 -0
  41. atdd/coder/conventions/backend.convention.yaml +460 -0
  42. atdd/coder/conventions/boundaries.convention.yaml +666 -0
  43. atdd/coder/conventions/commons.convention.yaml +460 -0
  44. atdd/coder/conventions/complexity.recipe.yaml +109 -0
  45. atdd/coder/conventions/component-naming.convention.yaml +178 -0
  46. atdd/coder/conventions/design.convention.yaml +327 -0
  47. atdd/coder/conventions/design.recipe.yaml +273 -0
  48. atdd/coder/conventions/dto.convention.yaml +660 -0
  49. atdd/coder/conventions/frontend.convention.yaml +542 -0
  50. atdd/coder/conventions/green.convention.yaml +1012 -0
  51. atdd/coder/conventions/presentation.convention.yaml +587 -0
  52. atdd/coder/conventions/refactor.convention.yaml +535 -0
  53. atdd/coder/conventions/technology.convention.yaml +206 -0
  54. atdd/coder/conventions/tests/__init__.py +0 -0
  55. atdd/coder/conventions/tests/test_adapter_recipe.py +302 -0
  56. atdd/coder/conventions/tests/test_complexity_recipe.py +289 -0
  57. atdd/coder/conventions/tests/test_component_taxonomy.py +278 -0
  58. atdd/coder/conventions/tests/test_component_urn_naming.py +165 -0
  59. atdd/coder/conventions/tests/test_thinness_recipe.py +286 -0
  60. atdd/coder/conventions/thinness.recipe.yaml +82 -0
  61. atdd/coder/conventions/train.convention.yaml +325 -0
  62. atdd/coder/conventions/verification.protocol.yaml +53 -0
  63. atdd/coder/schemas/design_system.schema.json +361 -0
  64. atdd/coder/validators/__init__.py +0 -0
  65. atdd/coder/validators/test_commons_structure.py +485 -0
  66. atdd/coder/validators/test_complexity.py +416 -0
  67. atdd/coder/validators/test_cross_language_consistency.py +431 -0
  68. atdd/coder/validators/test_design_system_compliance.py +413 -0
  69. atdd/coder/validators/test_dto_testing_patterns.py +268 -0
  70. atdd/coder/validators/test_green_cross_stack_layers.py +168 -0
  71. atdd/coder/validators/test_green_layer_dependencies.py +148 -0
  72. atdd/coder/validators/test_green_python_layer_structure.py +103 -0
  73. atdd/coder/validators/test_green_supabase_layer_structure.py +103 -0
  74. atdd/coder/validators/test_import_boundaries.py +396 -0
  75. atdd/coder/validators/test_init_file_urns.py +593 -0
  76. atdd/coder/validators/test_preact_layer_boundaries.py +221 -0
  77. atdd/coder/validators/test_presentation_convention.py +260 -0
  78. atdd/coder/validators/test_python_architecture.py +674 -0
  79. atdd/coder/validators/test_quality_metrics.py +420 -0
  80. atdd/coder/validators/test_station_master_pattern.py +244 -0
  81. atdd/coder/validators/test_train_infrastructure.py +454 -0
  82. atdd/coder/validators/test_train_urns.py +293 -0
  83. atdd/coder/validators/test_typescript_architecture.py +616 -0
  84. atdd/coder/validators/test_usecase_structure.py +421 -0
  85. atdd/coder/validators/test_wagon_boundaries.py +586 -0
  86. atdd/conftest.py +126 -0
  87. atdd/planner/__init__.py +1 -0
  88. atdd/planner/conventions/acceptance.convention.yaml +538 -0
  89. atdd/planner/conventions/appendix.convention.yaml +187 -0
  90. atdd/planner/conventions/artifact-naming.convention.yaml +852 -0
  91. atdd/planner/conventions/component.convention.yaml +670 -0
  92. atdd/planner/conventions/criteria.convention.yaml +141 -0
  93. atdd/planner/conventions/feature.convention.yaml +371 -0
  94. atdd/planner/conventions/interface.convention.yaml +382 -0
  95. atdd/planner/conventions/steps.convention.yaml +141 -0
  96. atdd/planner/conventions/train.convention.yaml +552 -0
  97. atdd/planner/conventions/wagon.convention.yaml +275 -0
  98. atdd/planner/conventions/wmbt.convention.yaml +258 -0
  99. atdd/planner/schemas/acceptance.schema.json +336 -0
  100. atdd/planner/schemas/appendix.schema.json +78 -0
  101. atdd/planner/schemas/component.schema.json +114 -0
  102. atdd/planner/schemas/feature.schema.json +197 -0
  103. atdd/planner/schemas/train.schema.json +192 -0
  104. atdd/planner/schemas/wagon.schema.json +281 -0
  105. atdd/planner/schemas/wmbt.schema.json +59 -0
  106. atdd/planner/validators/__init__.py +0 -0
  107. atdd/planner/validators/conftest.py +5 -0
  108. atdd/planner/validators/test_draft_wagon_registry.py +374 -0
  109. atdd/planner/validators/test_plan_cross_refs.py +240 -0
  110. atdd/planner/validators/test_plan_uniqueness.py +224 -0
  111. atdd/planner/validators/test_plan_urn_resolution.py +268 -0
  112. atdd/planner/validators/test_plan_wagons.py +174 -0
  113. atdd/planner/validators/test_train_validation.py +514 -0
  114. atdd/planner/validators/test_wagon_urn_chain.py +648 -0
  115. atdd/planner/validators/test_wmbt_consistency.py +327 -0
  116. atdd/planner/validators/test_wmbt_vocabulary.py +632 -0
  117. atdd/tester/__init__.py +1 -0
  118. atdd/tester/conventions/artifact.convention.yaml +257 -0
  119. atdd/tester/conventions/contract.convention.yaml +1009 -0
  120. atdd/tester/conventions/filename.convention.yaml +555 -0
  121. atdd/tester/conventions/migration.convention.yaml +509 -0
  122. atdd/tester/conventions/red.convention.yaml +797 -0
  123. atdd/tester/conventions/routing.convention.yaml +51 -0
  124. atdd/tester/conventions/telemetry.convention.yaml +458 -0
  125. atdd/tester/schemas/a11y.tmpl.json +17 -0
  126. atdd/tester/schemas/artifact.schema.json +189 -0
  127. atdd/tester/schemas/contract.schema.json +591 -0
  128. atdd/tester/schemas/contract.tmpl.json +95 -0
  129. atdd/tester/schemas/db.tmpl.json +20 -0
  130. atdd/tester/schemas/e2e.tmpl.json +17 -0
  131. atdd/tester/schemas/edge_function.tmpl.json +17 -0
  132. atdd/tester/schemas/event.tmpl.json +17 -0
  133. atdd/tester/schemas/http.tmpl.json +19 -0
  134. atdd/tester/schemas/job.tmpl.json +18 -0
  135. atdd/tester/schemas/load.tmpl.json +21 -0
  136. atdd/tester/schemas/metric.tmpl.json +19 -0
  137. atdd/tester/schemas/pack.schema.json +139 -0
  138. atdd/tester/schemas/realtime.tmpl.json +20 -0
  139. atdd/tester/schemas/rls.tmpl.json +18 -0
  140. atdd/tester/schemas/script.tmpl.json +16 -0
  141. atdd/tester/schemas/sec.tmpl.json +18 -0
  142. atdd/tester/schemas/storage.tmpl.json +18 -0
  143. atdd/tester/schemas/telemetry.schema.json +128 -0
  144. atdd/tester/schemas/telemetry_tracking_manifest.schema.json +143 -0
  145. atdd/tester/schemas/test_filename.schema.json +194 -0
  146. atdd/tester/schemas/test_intent.schema.json +179 -0
  147. atdd/tester/schemas/unit.tmpl.json +18 -0
  148. atdd/tester/schemas/visual.tmpl.json +18 -0
  149. atdd/tester/schemas/ws.tmpl.json +17 -0
  150. atdd/tester/utils/__init__.py +0 -0
  151. atdd/tester/utils/filename.py +300 -0
  152. atdd/tester/validators/__init__.py +0 -0
  153. atdd/tester/validators/cleanup_duplicate_headers.py +116 -0
  154. atdd/tester/validators/cleanup_duplicate_headers_v2.py +135 -0
  155. atdd/tester/validators/conftest.py +5 -0
  156. atdd/tester/validators/coverage_gap_report.py +321 -0
  157. atdd/tester/validators/fix_dual_ac_references.py +179 -0
  158. atdd/tester/validators/remove_duplicate_lines.py +93 -0
  159. atdd/tester/validators/test_acceptance_urn_filename_mapping.py +359 -0
  160. atdd/tester/validators/test_acceptance_urn_separator.py +166 -0
  161. atdd/tester/validators/test_artifact_naming_category.py +307 -0
  162. atdd/tester/validators/test_contract_schema_compliance.py +706 -0
  163. atdd/tester/validators/test_contracts_structure.py +200 -0
  164. atdd/tester/validators/test_coverage_adequacy.py +797 -0
  165. atdd/tester/validators/test_dual_ac_reference.py +225 -0
  166. atdd/tester/validators/test_fixture_validity.py +372 -0
  167. atdd/tester/validators/test_isolation.py +487 -0
  168. atdd/tester/validators/test_migration_coverage.py +204 -0
  169. atdd/tester/validators/test_migration_criteria.py +276 -0
  170. atdd/tester/validators/test_migration_generation.py +116 -0
  171. atdd/tester/validators/test_python_test_naming.py +410 -0
  172. atdd/tester/validators/test_red_layer_validation.py +95 -0
  173. atdd/tester/validators/test_red_python_layer_structure.py +87 -0
  174. atdd/tester/validators/test_red_supabase_layer_structure.py +90 -0
  175. atdd/tester/validators/test_telemetry_structure.py +634 -0
  176. atdd/tester/validators/test_typescript_test_naming.py +301 -0
  177. atdd/tester/validators/test_typescript_test_structure.py +84 -0
  178. atdd-0.1.0.dist-info/METADATA +191 -0
  179. atdd-0.1.0.dist-info/RECORD +183 -0
  180. atdd-0.1.0.dist-info/WHEEL +5 -0
  181. atdd-0.1.0.dist-info/entry_points.txt +2 -0
  182. atdd-0.1.0.dist-info/licenses/LICENSE +674 -0
  183. atdd-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,460 @@
1
+ version: "1.0"
2
+ name: "Commons Convention"
3
+ description: |
4
+ Cross-stack commons module structure for shared utilities.
5
+ Defines consistent naming and architecture patterns for shared code across Python and Frontend.
6
+
7
+ rationale: |
8
+ Wagons share cross-cutting concerns (validation, events, HTTP clients, auth) that don't belong
9
+ to any single wagon. The 'commons' module provides a canonical location for these utilities
10
+ with consistent naming across all technology stacks.
11
+
12
+ ARCHITECTURAL PRINCIPLES:
13
+ - Use 'commons' consistently across Python and Frontend (not 'shared' or 'core')
14
+ - Dependencies point inward: integration -> application -> domain
15
+ - Domain layer must be framework-agnostic (no preact, flask, etc.)
16
+
17
+ STRUCTURAL PATTERN DIVERGENCE (Intentional):
18
+ Python uses FEATURE-FIRST organization:
19
+ - Complex features (events/) have their own layers internally
20
+ - Simple utilities (resilience/, validation.py) are flat
21
+ - Matches Python package ecosystem conventions
22
+
23
+ Frontend uses LAYER-FIRST organization:
24
+ - All code organized by architectural layer at root
25
+ - Enables structural enforcement of layer dependencies
26
+ - Matches React/Preact ecosystem conventions
27
+
28
+ Both patterns enforce the same dependency rules; only the directory structure differs.
29
+
30
+ # ============================================================================
31
+ # STRUCTURAL PATTERN RATIONALE
32
+ # ============================================================================
33
+
34
+ structure_patterns:
35
+ divergence_rationale: |
36
+ The Python and Frontend commons use different organizational patterns.
37
+ This is INTENTIONAL and reflects ecosystem conventions and complexity differences.
38
+
39
+ python:
40
+ pattern: "feature-first"
41
+ description: |
42
+ Complex shared features use wagon-like structure with internal layers.
43
+ Simple utilities are flat at the commons root.
44
+
45
+ rationale:
46
+ - events/ is a complex feature with ports and adapters (mini-wagon pattern)
47
+ - resilience/ contains simple utilities (retry, circuit_breaker) - flat is appropriate
48
+ - validation.py is a pure utility - flat is appropriate
49
+ - Matches Python package ecosystem conventions
50
+
51
+ categories:
52
+ complex_features:
53
+ description: "Features with ports/adapters use internal layer structure"
54
+ examples:
55
+ - path: "events/"
56
+ structure: "events/src/{application/ports, integration/queues}"
57
+ reason: "Event bus abstraction needs port/adapter separation"
58
+
59
+ simple_utilities:
60
+ description: "Pure utilities are flat at commons root"
61
+ examples:
62
+ - path: "resilience/"
63
+ contents: ["retry.py", "circuit_breaker.py"]
64
+ reason: "No layering needed for pure utility functions"
65
+ - path: "validation.py"
66
+ reason: "Single-file utility for validation types"
67
+
68
+ shared_types:
69
+ description: "Domain types shared across features"
70
+ examples:
71
+ - path: "domain/enums/"
72
+ reason: "Enumerations used by multiple wagons"
73
+
74
+ frontend:
75
+ pattern: "layer-first"
76
+ description: |
77
+ All shared code organized by architectural layer at the root level.
78
+ Features are spread across layers but grouped by subdirectory within each layer.
79
+
80
+ rationale:
81
+ - Explicit layer directories enable structural auditing (domain has no framework imports)
82
+ - Matches React/Preact ecosystem patterns (hooks/, context/, etc.)
83
+ - Frontend cross-cutting concerns are simpler than backend
84
+ - TypeScript path aliases work well with layer-based imports (@commons/domain)
85
+
86
+ categories:
87
+ domain_layer:
88
+ description: "Framework-agnostic types and errors"
89
+ contents:
90
+ - "domain/auth/types.ts" # User, AuthContextValue
91
+ - "domain/errors.ts" # ApiError, NotFoundError, etc.
92
+ audit: "No preact, react, or @tanstack imports allowed"
93
+
94
+ application_layer:
95
+ description: "Hooks, context, orchestration"
96
+ contents:
97
+ - "application/auth/" # AuthContext, AuthProvider, useAuth
98
+ - "application/query/" # QueryClientConfig
99
+ audit: "May import from domain, preact/hooks allowed"
100
+
101
+ integration_layer:
102
+ description: "External clients and adapters"
103
+ contents:
104
+ - "integration/http/" # HttpClient
105
+ - "integration/supabase/" # Supabase client
106
+ audit: "May import from domain and application"
107
+
108
+ common_principles:
109
+ - principle: "Domain layer purity"
110
+ description: "Domain layer has no framework imports in both stacks"
111
+ python_enforcement: "No flask, fastapi, django imports"
112
+ frontend_enforcement: "No preact, react, @tanstack, @maintain-ux imports"
113
+
114
+ - principle: "Dependency direction"
115
+ description: "Dependencies point inward: integration -> application -> domain"
116
+ applies_to: "Both stacks"
117
+
118
+ - principle: "Consistent naming"
119
+ description: "Use 'commons' (not 'shared', 'core', 'lib') in all stacks"
120
+ applies_to: "Both stacks"
121
+
122
+ cross_references:
123
+ backend_layers:
124
+ - file: "backend.convention.yaml"
125
+ note: "Defines 4-layer architecture (domain, application, integration, presentation)"
126
+
127
+ frontend_layers:
128
+ - file: "frontend.convention.yaml"
129
+ note: "Defines frontend-specific layer patterns"
130
+
131
+ wagon_boundaries:
132
+ - file: "boundaries.convention.yaml"
133
+ note: "Defines qualified import patterns"
134
+
135
+ # ============================================================================
136
+ # NAMING CONVENTION
137
+ # ============================================================================
138
+
139
+ naming:
140
+ canonical_name: "commons"
141
+ description: "Use 'commons' consistently across all technology stacks"
142
+
143
+ paths:
144
+ python: "python/commons/"
145
+ frontend: "web/src/commons/"
146
+ supabase: "supabase/functions/commons/"
147
+
148
+ forbidden_names:
149
+ - "shared" # Inconsistent with Python
150
+ - "core" # Too generic
151
+ - "common" # Singular form
152
+ - "utils" # Implies utility functions only
153
+ - "lib" # Too generic
154
+
155
+ path_aliases:
156
+ frontend:
157
+ alias: "@commons"
158
+ resolution: "./src/commons"
159
+ config_files:
160
+ - "web/tsconfig.json"
161
+ - "web/vite.config.ts"
162
+
163
+ # ============================================================================
164
+ # LAYER STRUCTURE
165
+ # ============================================================================
166
+
167
+ layers:
168
+ domain:
169
+ description: "Framework-agnostic types, entities, errors, value objects"
170
+ allowed_imports: []
171
+ forbidden_imports:
172
+ python: ["flask", "fastapi", "django"]
173
+ frontend: ["preact", "react", "@tanstack", "@maintain-ux"]
174
+
175
+ python_contents:
176
+ - "domain/enums/" # Shared enumerations
177
+ - "validation.py" # ValidationResult, Result[T]
178
+
179
+ frontend_contents:
180
+ - "domain/auth/types.ts" # User, AuthContextValue
181
+ - "domain/errors.ts" # ApiError, NotFoundError, etc.
182
+
183
+ component_suffixes:
184
+ python: ["*.py"]
185
+ frontend: ["*types.ts", "*-vo.ts", "errors.ts"]
186
+
187
+ application:
188
+ description: "Hooks, context, orchestration logic, ports"
189
+ allowed_imports: ["domain"]
190
+ forbidden_imports:
191
+ frontend: ["preact"] # Only preact/hooks allowed, not preact core
192
+
193
+ python_contents:
194
+ - "events/src/application/ports/" # EventBusPort
195
+
196
+ frontend_contents:
197
+ - "application/auth/" # AuthContext, AuthProvider, useAuth
198
+ - "application/query/" # QueryClientConfig
199
+
200
+ component_suffixes:
201
+ python: ["*_port.py", "*_service.py", "protocols.py"]
202
+ frontend: ["*Context.tsx", "*Provider.tsx", "use*.ts", "*Config.ts"]
203
+
204
+ integration:
205
+ description: "External clients, adapters, infrastructure implementations"
206
+ allowed_imports: ["domain", "application"]
207
+
208
+ python_contents:
209
+ - "events/src/integration/queues/" # InMemoryEventQueue
210
+ - "events/src/integration/adapters/" # Event adapters
211
+ - "resilience/" # retry.py, circuit_breaker.py
212
+
213
+ frontend_contents:
214
+ - "integration/http/" # HttpClient
215
+ - "integration/supabase/" # Supabase client singleton
216
+
217
+ component_suffixes:
218
+ python: ["*_client.py", "*_adapter.py", "*_queue.py", "*_repository.py"]
219
+ frontend: ["*Client.ts", "*-client.ts", "client.ts"]
220
+
221
+ # ============================================================================
222
+ # DEPENDENCY RULES
223
+ # ============================================================================
224
+
225
+ dependency_rules:
226
+ description: "Dependencies point inward only"
227
+
228
+ allowed_edges:
229
+ - from: application
230
+ to: [domain]
231
+ - from: integration
232
+ to: [domain, application]
233
+
234
+ forbidden_edges:
235
+ - from: domain
236
+ to: [application, integration]
237
+ reason: "Domain must be pure - no external dependencies"
238
+
239
+ - from: application
240
+ to: [integration]
241
+ reason: "Application uses ports; integration implements them"
242
+
243
+ # ============================================================================
244
+ # STACK-SPECIFIC PATTERNS
245
+ # ============================================================================
246
+
247
+ stacks:
248
+ python:
249
+ path: "python/commons/"
250
+ structure: |
251
+ python/commons/
252
+ ├── __init__.py # urn:jel:commons
253
+ ├── validation.py # Domain: ValidationResult, Result[T]
254
+ ├── domain/
255
+ │ └── enums/ # Domain: Shared enumerations
256
+ ├── events/
257
+ │ └── src/
258
+ │ ├── application/ports/ # Application: EventBusPort
259
+ │ └── integration/
260
+ │ ├── queues/ # Integration: InMemoryEventQueue
261
+ │ └── adapters/ # Integration: Event adapters
262
+ └── resilience/
263
+ ├── retry.py # Integration: Retry with backoff
264
+ └── circuit_breaker.py # Integration: Circuit breaker
265
+
266
+ frontend:
267
+ path: "web/src/commons/"
268
+ structure: |
269
+ web/src/commons/
270
+ ├── index.ts # Public API barrel
271
+ ├── domain/
272
+ │ ├── index.ts # Domain exports
273
+ │ ├── auth/
274
+ │ │ └── types.ts # User, AuthContextValue
275
+ │ └── errors.ts # ApiError, NotFoundError, etc.
276
+ ├── application/
277
+ │ ├── index.ts # Application exports
278
+ │ ├── auth/
279
+ │ │ ├── index.ts
280
+ │ │ ├── AuthContext.tsx
281
+ │ │ ├── AuthProvider.tsx
282
+ │ │ └── useAuth.ts
283
+ │ └── query/
284
+ │ ├── index.ts
285
+ │ └── QueryClientConfig.ts
286
+ └── integration/
287
+ ├── index.ts # Integration exports
288
+ ├── http/
289
+ │ ├── index.ts
290
+ │ └── HttpClient.ts
291
+ └── supabase/
292
+ ├── index.ts
293
+ └── client.ts
294
+
295
+ # ============================================================================
296
+ # IMPORT PATTERNS
297
+ # ============================================================================
298
+
299
+ import_patterns:
300
+ frontend:
301
+ from_wagons:
302
+ description: "Import from @commons/{layer}"
303
+ examples:
304
+ - "import { HttpClient } from '@commons/integration';"
305
+ - "import { NotFoundError } from '@commons/domain';"
306
+ - "import { useAuth, AuthProvider } from '@commons/application';"
307
+
308
+ forbidden:
309
+ - pattern: "@shared/*"
310
+ reason: "Legacy naming - use @commons instead"
311
+ - pattern: "../shared/*"
312
+ reason: "Legacy relative import - use @commons alias"
313
+ - pattern: "./shared/*"
314
+ reason: "Legacy relative import - use @commons alias"
315
+
316
+ python:
317
+ from_wagons:
318
+ description: "Import with qualified path from commons"
319
+ examples:
320
+ - "from commons.validation import ValidationResult"
321
+ - "from commons.events.src.application.ports.event_bus_port import EventBusPort"
322
+ - "from commons.resilience.retry import retry_with_backoff"
323
+
324
+ # ============================================================================
325
+ # ENFORCEMENT
326
+ # ============================================================================
327
+
328
+ enforcement:
329
+ validators:
330
+ location: "atdd/coder/validators/test_commons_structure.py"
331
+
332
+ specs:
333
+ # Cross-stack validation
334
+ - id: "SPEC-CODER-COMMONS-0001"
335
+ description: "Commons exists in both Python and Frontend"
336
+ validates: "Consistent naming across stacks"
337
+
338
+ - id: "SPEC-CODER-COMMONS-0003"
339
+ description: "Old 'shared' directory does not exist"
340
+ validates: "Migration from shared to commons complete"
341
+
342
+ # Frontend structure validation (layer-first)
343
+ - id: "SPEC-CODER-COMMONS-0002"
344
+ description: "Frontend commons has domain/application/integration layers"
345
+ validates: "Layer-first structure for frontend"
346
+
347
+ - id: "SPEC-CODER-COMMONS-0004"
348
+ description: "Path aliases use @commons not @shared"
349
+ validates: "Correct path alias configuration"
350
+
351
+ - id: "SPEC-CODER-COMMONS-0005"
352
+ description: "No imports from @shared or ./shared"
353
+ validates: "All imports migrated to @commons"
354
+
355
+ - id: "SPEC-CODER-COMMONS-0006"
356
+ description: "Frontend domain layer has no framework imports"
357
+ validates: "Domain layer purity (no preact, react, @tanstack)"
358
+
359
+ - id: "SPEC-CODER-COMMONS-0007"
360
+ description: "Frontend commons has proper barrel exports (index.ts)"
361
+ validates: "Public API structure"
362
+
363
+ # Python structure validation (feature-first)
364
+ - id: "SPEC-CODER-COMMONS-0008"
365
+ description: "Python commons has __init__.py files"
366
+ validates: "Python package structure"
367
+
368
+ - id: "SPEC-CODER-COMMONS-0009"
369
+ description: "Python events feature has internal layer structure"
370
+ validates: "Feature-first pattern for complex features"
371
+
372
+ - id: "SPEC-CODER-COMMONS-0010"
373
+ description: "Python resilience is flat (no internal layers)"
374
+ validates: "Flat structure for simple utilities"
375
+
376
+ - id: "SPEC-CODER-COMMONS-0011"
377
+ description: "Python domain layer has no framework imports"
378
+ validates: "Domain layer purity (no flask, fastapi, django)"
379
+
380
+ ci_checks:
381
+ - name: "commons_naming"
382
+ description: "Verify 'commons' naming used, not 'shared'"
383
+
384
+ - name: "commons_frontend_layers"
385
+ description: "Verify layer-first structure in frontend commons"
386
+
387
+ - name: "commons_python_features"
388
+ description: "Verify feature-first structure in python commons"
389
+
390
+ - name: "commons_imports"
391
+ description: "Verify @commons path alias used"
392
+
393
+ - name: "commons_domain_purity"
394
+ description: "Verify domain layers have no framework imports"
395
+
396
+ # ============================================================================
397
+ # MIGRATION GUIDE
398
+ # ============================================================================
399
+
400
+ migration:
401
+ from_shared_to_commons:
402
+ description: "Steps to migrate from 'shared' to 'commons' naming"
403
+
404
+ steps:
405
+ - step: 1
406
+ action: "Create commons directory with 3-layer structure"
407
+ command: |
408
+ mkdir -p web/src/commons/domain/auth
409
+ mkdir -p web/src/commons/application/auth
410
+ mkdir -p web/src/commons/application/query
411
+ mkdir -p web/src/commons/integration/http
412
+ mkdir -p web/src/commons/integration/supabase
413
+
414
+ - step: 2
415
+ action: "Move files to appropriate layers"
416
+ mapping:
417
+ - from: "shared/auth/types.ts"
418
+ to: "commons/domain/auth/types.ts"
419
+ - from: "shared/api/errors.ts"
420
+ to: "commons/domain/errors.ts"
421
+ - from: "shared/auth/AuthContext.tsx"
422
+ to: "commons/application/auth/AuthContext.tsx"
423
+ - from: "shared/auth/useAuth.ts"
424
+ to: "commons/application/auth/useAuth.ts"
425
+ - from: "shared/auth/AuthProvider.tsx"
426
+ to: "commons/application/auth/AuthProvider.tsx"
427
+ - from: "shared/query/QueryClientConfig.ts"
428
+ to: "commons/application/query/QueryClientConfig.ts"
429
+ - from: "shared/api/HttpClient.ts"
430
+ to: "commons/integration/http/HttpClient.ts"
431
+ - from: "shared/supabase/client.ts"
432
+ to: "commons/integration/supabase/client.ts"
433
+
434
+ - step: 3
435
+ action: "Update path aliases in config files"
436
+ files:
437
+ - "web/tsconfig.json"
438
+ - "web/vite.config.ts"
439
+ change: "@shared -> @commons"
440
+
441
+ - step: 4
442
+ action: "Update all imports"
443
+ patterns:
444
+ - from: "@shared/api"
445
+ to: "@commons/integration"
446
+ - from: "@shared/auth"
447
+ to: "@commons/application"
448
+ - from: "../shared/auth"
449
+ to: "@commons/application"
450
+
451
+ - step: 5
452
+ action: "Delete old shared directory"
453
+ command: "rm -rf web/src/shared"
454
+
455
+ - step: 6
456
+ action: "Run verification"
457
+ commands:
458
+ - "cd web && npx tsc --noEmit"
459
+ - "cd web && npm test"
460
+ - "./atdd/atdd.py --test coder -k commons"
@@ -0,0 +1,109 @@
1
+ recipe: complexity
2
+ pattern: "Complexity Reduction (Split/Extract)"
3
+ category: domain
4
+ source: "Refactoring: Improving the Design of Existing Code (Martin Fowler)"
5
+ utils: "complexity.py"
6
+
7
+ applies_when:
8
+ - "ATDD audit flags excessive complexity"
9
+ - "Complex boolean conditionals (cyclomatic > 10)"
10
+
11
+ steps:
12
+ - step: 1
13
+ what: "Create base complexity reduction interface"
14
+ where: "domain/complexity/base.py"
15
+ template: |
16
+ class ComplexityRule:
17
+ """Base class for composable complexity reduction rules."""
18
+
19
+ def is_satisfied_by(self, candidate) -> bool:
20
+ """Check if candidate satisfies this rule."""
21
+ raise NotImplementedError
22
+
23
+ def and_(self, other: 'ComplexityRule') -> 'ComplexityRule':
24
+ return AndRule(self, other)
25
+
26
+ def or_(self, other: 'ComplexityRule') -> 'ComplexityRule':
27
+ return OrRule(self, other)
28
+
29
+ def not_(self) -> 'ComplexityRule':
30
+ return NotRule(self)
31
+
32
+
33
+ class AndRule(ComplexityRule):
34
+ def __init__(self, left: ComplexityRule, right: ComplexityRule):
35
+ self.left = left
36
+ self.right = right
37
+
38
+ def is_satisfied_by(self, candidate) -> bool:
39
+ return self.left.is_satisfied_by(candidate) and self.right.is_satisfied_by(candidate)
40
+
41
+
42
+ class OrRule(ComplexityRule):
43
+ def __init__(self, left: ComplexityRule, right: ComplexityRule):
44
+ self.left = left
45
+ self.right = right
46
+
47
+ def is_satisfied_by(self, candidate) -> bool:
48
+ return self.left.is_satisfied_by(candidate) or self.right.is_satisfied_by(candidate)
49
+
50
+
51
+ class NotRule(ComplexityRule):
52
+ def __init__(self, rule: ComplexityRule):
53
+ self.rule = rule
54
+
55
+ def is_satisfied_by(self, candidate) -> bool:
56
+ return not self.rule.is_satisfied_by(candidate)
57
+
58
+ - step: 2
59
+ what: "Extract each complex conditional to named rule class"
60
+ where: "domain/complexity/{rule}.py"
61
+ example: |
62
+ # Before (complex conditional):
63
+ if customer.is_premium and order.total > 1000 or customer.is_first_time:
64
+ apply_discount()
65
+
66
+ # After (extract to rules):
67
+ class IsPremiumCustomerRule(ComplexityRule):
68
+ def is_satisfied_by(self, candidate) -> bool:
69
+ return candidate['customer'].is_premium
70
+
71
+ class MinimumOrderRule(ComplexityRule):
72
+ def __init__(self, min_amount: Money):
73
+ self.min_amount = min_amount
74
+
75
+ def is_satisfied_by(self, candidate) -> bool:
76
+ return candidate['order'].total >= self.min_amount
77
+
78
+ class IsFirstTimeCustomerRule(ComplexityRule):
79
+ def is_satisfied_by(self, candidate) -> bool:
80
+ return candidate['customer'].is_first_time
81
+
82
+ - step: 3
83
+ what: "Compose complexity rules with and_/or_/not_"
84
+ template: |
85
+ # Compose
86
+ eligible_for_discount = (
87
+ IsPremiumCustomerRule()
88
+ .and_(MinimumOrderRule(Money.from_dollars(1000)))
89
+ .or_(IsFirstTimeCustomerRule())
90
+ )
91
+
92
+ # Use
93
+ if eligible_for_discount.is_satisfied_by({'customer': customer, 'order': order}):
94
+ apply_discount()
95
+
96
+ verify:
97
+ - run: pytest -xvs tests/domain/complexity/
98
+ expect: GREEN
99
+
100
+ requirements:
101
+ - "Complexity rules MUST be side-effect free (pure functions)"
102
+ - "Each rule testable in isolation"
103
+ - "Composition works (and_/or_/not_)"
104
+
105
+ final_verify:
106
+ - "Cyclomatic complexity reduced below threshold"
107
+ - "Boolean logic is explicit and named"
108
+ - "Rules reusable across validation/filtering/queries"
109
+ - "All tests GREEN"