atdd 0.2.1__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 (184) hide show
  1. atdd/__init__.py +6 -0
  2. atdd/__main__.py +4 -0
  3. atdd/cli.py +404 -0
  4. atdd/coach/__init__.py +0 -0
  5. atdd/coach/commands/__init__.py +0 -0
  6. atdd/coach/commands/add_persistence_metadata.py +215 -0
  7. atdd/coach/commands/analyze_migrations.py +188 -0
  8. atdd/coach/commands/consumers.py +720 -0
  9. atdd/coach/commands/infer_governance_status.py +149 -0
  10. atdd/coach/commands/initializer.py +177 -0
  11. atdd/coach/commands/interface.py +1078 -0
  12. atdd/coach/commands/inventory.py +565 -0
  13. atdd/coach/commands/migration.py +240 -0
  14. atdd/coach/commands/registry.py +1560 -0
  15. atdd/coach/commands/session.py +430 -0
  16. atdd/coach/commands/sync.py +405 -0
  17. atdd/coach/commands/test_interface.py +399 -0
  18. atdd/coach/commands/test_runner.py +141 -0
  19. atdd/coach/commands/tests/__init__.py +1 -0
  20. atdd/coach/commands/tests/test_telemetry_array_validation.py +235 -0
  21. atdd/coach/commands/traceability.py +4264 -0
  22. atdd/coach/conventions/session.convention.yaml +754 -0
  23. atdd/coach/overlays/__init__.py +2 -0
  24. atdd/coach/overlays/claude.md +2 -0
  25. atdd/coach/schemas/config.schema.json +34 -0
  26. atdd/coach/schemas/manifest.schema.json +101 -0
  27. atdd/coach/templates/ATDD.md +282 -0
  28. atdd/coach/templates/SESSION-TEMPLATE.md +327 -0
  29. atdd/coach/utils/__init__.py +0 -0
  30. atdd/coach/utils/graph/__init__.py +0 -0
  31. atdd/coach/utils/graph/urn.py +875 -0
  32. atdd/coach/validators/__init__.py +0 -0
  33. atdd/coach/validators/shared_fixtures.py +365 -0
  34. atdd/coach/validators/test_enrich_wagon_registry.py +167 -0
  35. atdd/coach/validators/test_registry.py +575 -0
  36. atdd/coach/validators/test_session_validation.py +1183 -0
  37. atdd/coach/validators/test_traceability.py +448 -0
  38. atdd/coach/validators/test_update_feature_paths.py +108 -0
  39. atdd/coach/validators/test_validate_contract_consumers.py +297 -0
  40. atdd/coder/__init__.py +1 -0
  41. atdd/coder/conventions/adapter.recipe.yaml +88 -0
  42. atdd/coder/conventions/backend.convention.yaml +460 -0
  43. atdd/coder/conventions/boundaries.convention.yaml +666 -0
  44. atdd/coder/conventions/commons.convention.yaml +460 -0
  45. atdd/coder/conventions/complexity.recipe.yaml +109 -0
  46. atdd/coder/conventions/component-naming.convention.yaml +178 -0
  47. atdd/coder/conventions/design.convention.yaml +327 -0
  48. atdd/coder/conventions/design.recipe.yaml +273 -0
  49. atdd/coder/conventions/dto.convention.yaml +660 -0
  50. atdd/coder/conventions/frontend.convention.yaml +542 -0
  51. atdd/coder/conventions/green.convention.yaml +1012 -0
  52. atdd/coder/conventions/presentation.convention.yaml +587 -0
  53. atdd/coder/conventions/refactor.convention.yaml +535 -0
  54. atdd/coder/conventions/technology.convention.yaml +206 -0
  55. atdd/coder/conventions/tests/__init__.py +0 -0
  56. atdd/coder/conventions/tests/test_adapter_recipe.py +302 -0
  57. atdd/coder/conventions/tests/test_complexity_recipe.py +289 -0
  58. atdd/coder/conventions/tests/test_component_taxonomy.py +278 -0
  59. atdd/coder/conventions/tests/test_component_urn_naming.py +165 -0
  60. atdd/coder/conventions/tests/test_thinness_recipe.py +286 -0
  61. atdd/coder/conventions/thinness.recipe.yaml +82 -0
  62. atdd/coder/conventions/train.convention.yaml +325 -0
  63. atdd/coder/conventions/verification.protocol.yaml +53 -0
  64. atdd/coder/schemas/design_system.schema.json +361 -0
  65. atdd/coder/validators/__init__.py +0 -0
  66. atdd/coder/validators/test_commons_structure.py +485 -0
  67. atdd/coder/validators/test_complexity.py +416 -0
  68. atdd/coder/validators/test_cross_language_consistency.py +431 -0
  69. atdd/coder/validators/test_design_system_compliance.py +413 -0
  70. atdd/coder/validators/test_dto_testing_patterns.py +268 -0
  71. atdd/coder/validators/test_green_cross_stack_layers.py +168 -0
  72. atdd/coder/validators/test_green_layer_dependencies.py +148 -0
  73. atdd/coder/validators/test_green_python_layer_structure.py +103 -0
  74. atdd/coder/validators/test_green_supabase_layer_structure.py +103 -0
  75. atdd/coder/validators/test_import_boundaries.py +396 -0
  76. atdd/coder/validators/test_init_file_urns.py +593 -0
  77. atdd/coder/validators/test_preact_layer_boundaries.py +221 -0
  78. atdd/coder/validators/test_presentation_convention.py +260 -0
  79. atdd/coder/validators/test_python_architecture.py +674 -0
  80. atdd/coder/validators/test_quality_metrics.py +420 -0
  81. atdd/coder/validators/test_station_master_pattern.py +244 -0
  82. atdd/coder/validators/test_train_infrastructure.py +454 -0
  83. atdd/coder/validators/test_train_urns.py +293 -0
  84. atdd/coder/validators/test_typescript_architecture.py +616 -0
  85. atdd/coder/validators/test_usecase_structure.py +421 -0
  86. atdd/coder/validators/test_wagon_boundaries.py +586 -0
  87. atdd/conftest.py +126 -0
  88. atdd/planner/__init__.py +1 -0
  89. atdd/planner/conventions/acceptance.convention.yaml +538 -0
  90. atdd/planner/conventions/appendix.convention.yaml +187 -0
  91. atdd/planner/conventions/artifact-naming.convention.yaml +852 -0
  92. atdd/planner/conventions/component.convention.yaml +670 -0
  93. atdd/planner/conventions/criteria.convention.yaml +141 -0
  94. atdd/planner/conventions/feature.convention.yaml +371 -0
  95. atdd/planner/conventions/interface.convention.yaml +382 -0
  96. atdd/planner/conventions/steps.convention.yaml +141 -0
  97. atdd/planner/conventions/train.convention.yaml +552 -0
  98. atdd/planner/conventions/wagon.convention.yaml +275 -0
  99. atdd/planner/conventions/wmbt.convention.yaml +258 -0
  100. atdd/planner/schemas/acceptance.schema.json +336 -0
  101. atdd/planner/schemas/appendix.schema.json +78 -0
  102. atdd/planner/schemas/component.schema.json +114 -0
  103. atdd/planner/schemas/feature.schema.json +197 -0
  104. atdd/planner/schemas/train.schema.json +192 -0
  105. atdd/planner/schemas/wagon.schema.json +281 -0
  106. atdd/planner/schemas/wmbt.schema.json +59 -0
  107. atdd/planner/validators/__init__.py +0 -0
  108. atdd/planner/validators/conftest.py +5 -0
  109. atdd/planner/validators/test_draft_wagon_registry.py +374 -0
  110. atdd/planner/validators/test_plan_cross_refs.py +240 -0
  111. atdd/planner/validators/test_plan_uniqueness.py +224 -0
  112. atdd/planner/validators/test_plan_urn_resolution.py +268 -0
  113. atdd/planner/validators/test_plan_wagons.py +174 -0
  114. atdd/planner/validators/test_train_validation.py +514 -0
  115. atdd/planner/validators/test_wagon_urn_chain.py +648 -0
  116. atdd/planner/validators/test_wmbt_consistency.py +327 -0
  117. atdd/planner/validators/test_wmbt_vocabulary.py +632 -0
  118. atdd/tester/__init__.py +1 -0
  119. atdd/tester/conventions/artifact.convention.yaml +257 -0
  120. atdd/tester/conventions/contract.convention.yaml +1009 -0
  121. atdd/tester/conventions/filename.convention.yaml +555 -0
  122. atdd/tester/conventions/migration.convention.yaml +509 -0
  123. atdd/tester/conventions/red.convention.yaml +797 -0
  124. atdd/tester/conventions/routing.convention.yaml +51 -0
  125. atdd/tester/conventions/telemetry.convention.yaml +458 -0
  126. atdd/tester/schemas/a11y.tmpl.json +17 -0
  127. atdd/tester/schemas/artifact.schema.json +189 -0
  128. atdd/tester/schemas/contract.schema.json +591 -0
  129. atdd/tester/schemas/contract.tmpl.json +95 -0
  130. atdd/tester/schemas/db.tmpl.json +20 -0
  131. atdd/tester/schemas/e2e.tmpl.json +17 -0
  132. atdd/tester/schemas/edge_function.tmpl.json +17 -0
  133. atdd/tester/schemas/event.tmpl.json +17 -0
  134. atdd/tester/schemas/http.tmpl.json +19 -0
  135. atdd/tester/schemas/job.tmpl.json +18 -0
  136. atdd/tester/schemas/load.tmpl.json +21 -0
  137. atdd/tester/schemas/metric.tmpl.json +19 -0
  138. atdd/tester/schemas/pack.schema.json +139 -0
  139. atdd/tester/schemas/realtime.tmpl.json +20 -0
  140. atdd/tester/schemas/rls.tmpl.json +18 -0
  141. atdd/tester/schemas/script.tmpl.json +16 -0
  142. atdd/tester/schemas/sec.tmpl.json +18 -0
  143. atdd/tester/schemas/storage.tmpl.json +18 -0
  144. atdd/tester/schemas/telemetry.schema.json +128 -0
  145. atdd/tester/schemas/telemetry_tracking_manifest.schema.json +143 -0
  146. atdd/tester/schemas/test_filename.schema.json +194 -0
  147. atdd/tester/schemas/test_intent.schema.json +179 -0
  148. atdd/tester/schemas/unit.tmpl.json +18 -0
  149. atdd/tester/schemas/visual.tmpl.json +18 -0
  150. atdd/tester/schemas/ws.tmpl.json +17 -0
  151. atdd/tester/utils/__init__.py +0 -0
  152. atdd/tester/utils/filename.py +300 -0
  153. atdd/tester/validators/__init__.py +0 -0
  154. atdd/tester/validators/cleanup_duplicate_headers.py +116 -0
  155. atdd/tester/validators/cleanup_duplicate_headers_v2.py +135 -0
  156. atdd/tester/validators/conftest.py +5 -0
  157. atdd/tester/validators/coverage_gap_report.py +321 -0
  158. atdd/tester/validators/fix_dual_ac_references.py +179 -0
  159. atdd/tester/validators/remove_duplicate_lines.py +93 -0
  160. atdd/tester/validators/test_acceptance_urn_filename_mapping.py +359 -0
  161. atdd/tester/validators/test_acceptance_urn_separator.py +166 -0
  162. atdd/tester/validators/test_artifact_naming_category.py +307 -0
  163. atdd/tester/validators/test_contract_schema_compliance.py +706 -0
  164. atdd/tester/validators/test_contracts_structure.py +200 -0
  165. atdd/tester/validators/test_coverage_adequacy.py +797 -0
  166. atdd/tester/validators/test_dual_ac_reference.py +225 -0
  167. atdd/tester/validators/test_fixture_validity.py +372 -0
  168. atdd/tester/validators/test_isolation.py +487 -0
  169. atdd/tester/validators/test_migration_coverage.py +204 -0
  170. atdd/tester/validators/test_migration_criteria.py +276 -0
  171. atdd/tester/validators/test_migration_generation.py +116 -0
  172. atdd/tester/validators/test_python_test_naming.py +410 -0
  173. atdd/tester/validators/test_red_layer_validation.py +95 -0
  174. atdd/tester/validators/test_red_python_layer_structure.py +87 -0
  175. atdd/tester/validators/test_red_supabase_layer_structure.py +90 -0
  176. atdd/tester/validators/test_telemetry_structure.py +634 -0
  177. atdd/tester/validators/test_typescript_test_naming.py +301 -0
  178. atdd/tester/validators/test_typescript_test_structure.py +84 -0
  179. atdd-0.2.1.dist-info/METADATA +221 -0
  180. atdd-0.2.1.dist-info/RECORD +184 -0
  181. atdd-0.2.1.dist-info/WHEEL +5 -0
  182. atdd-0.2.1.dist-info/entry_points.txt +2 -0
  183. atdd-0.2.1.dist-info/licenses/LICENSE +674 -0
  184. atdd-0.2.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,535 @@
1
+ schema_version: "1.0.1"
2
+ convention_id: "coder.refactor"
3
+ name: "REFACTOR Phase Convention"
4
+ description: "Transformation process and quality standards for refactoring GREEN code to clean architecture."
5
+
6
+ refactor_phase:
7
+ goal: "Preserve behavior; enforce architecture, clarity, and sustainability"
8
+
9
+ principles:
10
+ - id: RP-01
11
+ text: "No new behavior without new tests"
12
+ - id: RP-02
13
+ text: "No test changes except renames/moves"
14
+ - id: RP-03
15
+ text: "Improve internal structure until changes are cheap"
16
+ - id: RP-04
17
+ text: "Enforce dependency rules strictly"
18
+
19
+ architecture_target:
20
+ description: "Target 4-layer clean architecture (defined in code-type-specific conventions)"
21
+ conventions:
22
+ frontend: "conventions:coder:frontend"
23
+ backend: "conventions:coder:backend"
24
+ note: "Layer definitions, component types, file suffixes, and dependency rules defined in frontend/backend conventions"
25
+
26
+ # Composition Root Pattern (Maintained During Refactoring)
27
+ composition_root:
28
+ description: "composition.py and wagon.py survive refactoring unchanged - they orchestrate refactored components"
29
+
30
+ refactoring_approach: |
31
+ During REFACTOR, composition roots are the LAST files to change:
32
+ 1. Refactor domain/application/integration/presentation layers
33
+ 2. Update imports in composition.py/wagon.py to point to new locations
34
+ 3. Composition logic stays the same (only import paths change)
35
+
36
+ hierarchy:
37
+ feature_level: "python/{wagon}/{feature}/composition.py"
38
+ wagon_level: "python/{wagon}/wagon.py"
39
+ train_level: "python/trains/runner.py (NEW in SESSION-12)"
40
+ application_level: "main.py or server.py (becomes Station Master)"
41
+
42
+ refactoring_workflow:
43
+ step_1:
44
+ action: "Refactor layers (domain, application, integration, presentation)"
45
+ note: "Move files to proper subdirectories, extract use cases, create ports"
46
+
47
+ step_2:
48
+ action: "Update composition.py imports to reflect new structure"
49
+ before: "from src.domain.timebank import Timebank"
50
+ after: "from src.domain.entities.timebank import Timebank"
51
+
52
+ step_3:
53
+ action: "Verify composition.py still works after refactoring"
54
+ command: "python3 python/{wagon}/{feature}/composition.py"
55
+ expectation: "Should run without errors"
56
+
57
+ step_4:
58
+ action: "Update wagon.py imports if features were restructured"
59
+ before: "from {wagon}.{feature}.src.domain.model import Model"
60
+ after: "from {wagon}.{feature}.src.domain.entities.model import Model"
61
+
62
+ step_5:
63
+ action: "Verify wagon.py orchestration after refactoring"
64
+ command: "python3 python/{wagon}/wagon.py"
65
+ expectation: "All features orchestrate correctly"
66
+
67
+ stability_principle: |
68
+ Composition roots provide STABILITY during refactoring:
69
+ - Features can be completely restructured internally
70
+ - As long as composition.py still works, external consumers are unaffected
71
+ - wagon.py provides integration regression testing during refactoring
72
+ - trains/runner.py orchestrates wagons for production user journeys (SESSION-12)
73
+
74
+ testing_strategy:
75
+ unit_tests: "Test refactored domain/application layers"
76
+ integration_tests: "Test via feature composition.py"
77
+ wagon_tests: "Test via wagon.py orchestration"
78
+ acceptance_tests: "Still GREEN throughout refactoring"
79
+
80
+ rich_cli_feedback:
81
+ description: "wagon.py should provide rich visual feedback during orchestration"
82
+ rationale: |
83
+ wagon.py is a manual test harness and demo tool.
84
+ Rich CLI feedback makes it:
85
+ - More engaging for stakeholder demos
86
+ - Easier to understand mechanic behavior
87
+ - Better for debugging and manual testing
88
+ - More professional and polished
89
+
90
+ standard_patterns:
91
+ real_time_simulation:
92
+ description: "Add delays to simulate real-world timing"
93
+ examples:
94
+ - "Animated dots during processing: 'Turn 1: ...'"
95
+ - "Small delays between steps (0.3s)"
96
+ - "Simulates user thinking time"
97
+
98
+ progress_visualization:
99
+ description: "Visual progress bars for time/resource depletion"
100
+ examples:
101
+ - "Color-coded progress bars (green/yellow/red)"
102
+ - "Percentage and absolute values shown"
103
+ - "Example: [████████░░░░] 80.0s / 100.0s"
104
+
105
+ status_indicators:
106
+ description: "Clear visual status with emojis and colors"
107
+ examples:
108
+ - "✅ Success indicators"
109
+ - "⚠️ Warning states"
110
+ - "🔴 Error/critical states"
111
+ - "📊 Status summaries"
112
+
113
+ structured_output:
114
+ description: "Organized output with headers and sections"
115
+ examples:
116
+ - "Section headers: ========"
117
+ - "Subsections with indentation"
118
+ - "Summary tables at end"
119
+
120
+ implementation_example: |
121
+ # Real-time simulation with progress bar
122
+ def show_progress_bar(current: float, total: float, width: int = 40):
123
+ percentage = current / total
124
+ filled = int(width * percentage)
125
+ bar = "█" * filled + "░" * (width - filled)
126
+
127
+ # Color coding
128
+ if percentage > 0.5:
129
+ color = "\033[92m" # Green
130
+ elif percentage > 0.2:
131
+ color = "\033[93m" # Yellow
132
+ else:
133
+ color = "\033[91m" # Red
134
+ reset = "\033[0m"
135
+
136
+ return f"{color}[{bar}]{reset} {current:.1f} / {total:.1f}"
137
+
138
+ # Animated processing
139
+ for turn in turns:
140
+ print(f" Turn {i}: ", end="", flush=True)
141
+ for _ in range(3):
142
+ print(".", end="", flush=True)
143
+ time.sleep(0.15)
144
+ print(f" {turn:.1f}s")
145
+ print(f" {show_progress_bar(remaining, total)}")
146
+ time.sleep(0.3)
147
+
148
+ when_to_add:
149
+ timing: "During REFACTOR phase (after GREEN is complete)"
150
+ scenarios:
151
+ - "Wagon orchestrates multiple features"
152
+ - "Time-based or resource-based mechanics"
153
+ - "Need for stakeholder demos"
154
+ - "Manual testing of complex flows"
155
+ not_needed:
156
+ - "Simple wagons with instant operations"
157
+ - "Pure library/utility wagons"
158
+ - "Wagons only used in automated tests"
159
+
160
+ actions:
161
+ - id: RF-DOMAIN
162
+ action: "Extract/move logic to Domain layer; keep it pure"
163
+ checklist:
164
+ - "Identify business rules currently in handlers/services"
165
+ - "Extract to pure functions/classes with no dependencies"
166
+ - "Create value objects for primitives (Email, Money, OrderId)"
167
+ - "Create entities with identity and lifecycle"
168
+ - "Move invariant validation into domain models"
169
+ verification:
170
+ - "Domain tests run without any infrastructure"
171
+ - "No imports from application/presentation/integration"
172
+ pattern: |
173
+ // Domain layer - Pure business logic
174
+ class Order {
175
+ private constructor(
176
+ public readonly id: OrderId,
177
+ public readonly items: OrderItem[],
178
+ public readonly total: Money
179
+ ) {}
180
+
181
+ static create(data: CreateOrderData): Order {
182
+ if (data.items.length === 0) {
183
+ throw new DomainException('Order must have at least one item')
184
+ }
185
+ // All business rules validated here
186
+ return new Order(...)
187
+ }
188
+
189
+ canBeCancelled(): boolean {
190
+ return this.status === 'pending' // Pure business logic
191
+ }
192
+ }
193
+ checks:
194
+ - type: import_scan
195
+ path: "domain/**"
196
+ forbid:
197
+ - "domain → application"
198
+ - "domain → presentation"
199
+ - "domain → integration"
200
+ - type: grep
201
+ path: "domain/**"
202
+ must_not_match:
203
+ - "import.*from.*['\"].*/(application|presentation|integration)"
204
+
205
+ - id: RF-USECASE
206
+ action: "Create Application use cases; inject ports"
207
+ checklist:
208
+ - "Define port interfaces for all I/O operations"
209
+ - "Create use case classes that orchestrate domain + ports"
210
+ - "Inject ports via constructor"
211
+ - "Keep use cases framework-agnostic"
212
+ pattern: |
213
+ // Application layer
214
+ interface OrderRepository { // Port
215
+ save(order: Order): Promise<void>
216
+ findById(id: OrderId): Promise<Order>
217
+ }
218
+
219
+ class CreateOrderUseCase {
220
+ constructor(
221
+ private orderRepo: OrderRepository, // Port injection
222
+ private paymentGateway: PaymentGateway
223
+ ) {}
224
+
225
+ async execute(data: CreateOrderInput): Promise<Order> {
226
+ const order = Order.create(data) // Domain logic
227
+ await this.paymentGateway.charge(order.total)
228
+ await this.orderRepo.save(order)
229
+ return order
230
+ }
231
+ }
232
+ checks:
233
+ - type: import_scan
234
+ path: "application/**"
235
+ forbid:
236
+ - "application → presentation"
237
+ - "application → integration (except port interfaces)"
238
+
239
+ - id: RF-PRESENTATION
240
+ action: "Extract presentation layer; handlers become thin"
241
+ checklist:
242
+ - "Move all handlers to presentation/"
243
+ - "Handlers only: parse request → call use case → format response"
244
+ - "Move DTOs/validators to presentation/"
245
+ - "No business logic in handlers"
246
+ pattern: |
247
+ // Presentation layer
248
+ async function handleCreateOrder(req: Request): Promise<Response> {
249
+ // 1. Parse & validate
250
+ const input = CreateOrderDTO.parse(req.body)
251
+
252
+ // 2. Call use case
253
+ const order = await createOrderUseCase.execute(input)
254
+
255
+ // 3. Format response
256
+ return { status: 201, body: OrderResponseDTO.from(order) }
257
+ }
258
+ checks:
259
+ - type: grep
260
+ path: "presentation/**"
261
+ must_not_match:
262
+ - "new PgClient\\("
263
+ - "new Pool\\("
264
+ - "axios\\."
265
+ - "fetch\\("
266
+ - "fs\\."
267
+
268
+ - id: RF-INFRA
269
+ action: "Implement ports in Integration layer; remove direct calls"
270
+ checklist:
271
+ - "Create concrete implementations of all ports"
272
+ - "Move DB/HTTP/file code to integration/"
273
+ - "Wire implementations via DI/factory"
274
+ - "Replace in-memory fakes with real adapters"
275
+ pattern: |
276
+ // Integration layer
277
+ class PostgresOrderRepository implements OrderRepository {
278
+ constructor(private db: Database) {}
279
+
280
+ async save(order: Order): Promise<void> {
281
+ const row = OrderMapper.toRow(order) // Map domain → DB
282
+ await this.db.insert('orders', row)
283
+ }
284
+
285
+ async findById(id: OrderId): Promise<Order> {
286
+ const row = await this.db.findOne('orders', { id: id.value })
287
+ return OrderMapper.toDomain(row) // Map DB → domain
288
+ }
289
+ }
290
+ checks:
291
+ - type: reference
292
+ note: "Verify every port interface has at least one adapter implementation"
293
+
294
+ - id: RF-SPLIT
295
+ action: "Split large functions; remove duplication; name precisely"
296
+ guidelines:
297
+ - "Functions < 20 lines"
298
+ - "Cyclomatic complexity < 10"
299
+ - "Extract helper functions"
300
+ - "Use descriptive names (no abbreviations)"
301
+ - "Apply DRY after 3rd occurrence"
302
+ checks:
303
+ - type: complexity_scan
304
+ max_cyclomatic: 10
305
+ max_function_lines: 30
306
+
307
+ - id: RF-ARCHTESTS
308
+ action: "Add boundary tests/lint to enforce layers"
309
+ examples:
310
+ - "Domain layer imports nothing"
311
+ - "Application layer doesn't import presentation/integration"
312
+ - "Integration implements all defined ports"
313
+ - "No cross-feature imports"
314
+ tools:
315
+ - "ESLint + eslint-plugin-boundaries"
316
+ - "ArchUnit (Java/Kotlin)"
317
+ - "dependency-cruiser (TypeScript)"
318
+ - "Custom import analyzer"
319
+
320
+ - id: RF-FAKES
321
+ action: "Replace in-memory fakes with real adapters (keep fakes for tests)"
322
+ strategy:
323
+ - "Production: wire real adapters (PostgresOrderRepo)"
324
+ - "Tests: keep using in-memory fakes (InMemoryOrderRepo)"
325
+ - "Both implement same port interface"
326
+
327
+ - id: RF-CROSSCUT
328
+ action: "Add logging/telemetry at edges; handle errors centrally"
329
+ patterns:
330
+ - "Middleware for request logging"
331
+ - "Centralized error handler"
332
+ - "Use case decorators for tracing"
333
+ - "Domain events for audit logs"
334
+
335
+ non_functional:
336
+ - id: NF-VALIDATION
337
+ requirement: "Centralized at Presentation/Application boundary"
338
+ pattern: |
339
+ // Presentation: syntax validation
340
+ class CreateOrderDTO {
341
+ @IsString() customerId: string
342
+ @IsArray() items: OrderItemDTO[]
343
+
344
+ static parse(raw: unknown): CreateOrderDTO {
345
+ // Validate structure & types
346
+ }
347
+ }
348
+
349
+ // Domain: semantic validation
350
+ class Order {
351
+ static create(data: CreateOrderInput): Order {
352
+ if (data.items.length === 0) {
353
+ throw new DomainException('Order must have at least one item')
354
+ }
355
+ // Business rules validated here
356
+ }
357
+ }
358
+
359
+ - id: NF-CONFIG
360
+ requirement: "Config via env; secrets via provider; no hardcoded creds"
361
+ pattern: |
362
+ // Integration layer
363
+ class DatabaseConfig {
364
+ static fromEnv(): DatabaseConfig {
365
+ return {
366
+ host: process.env.DB_HOST,
367
+ password: secretsManager.get('DB_PASSWORD') // Not hardcoded
368
+ }
369
+ }
370
+ }
371
+
372
+ - id: NF-PERF
373
+ requirement: "Only optimize where profiling shows need"
374
+ approach:
375
+ - "Profile first"
376
+ - "Optimize hot paths only"
377
+ - "Add caching strategically"
378
+ - "Don't sacrifice clarity for premature optimization"
379
+
380
+ - id: NF-ERRORS
381
+ requirement: "Domain errors vs infrastructure errors"
382
+ pattern: |
383
+ // Domain errors (expected)
384
+ class OrderAlreadyShippedException extends DomainException {}
385
+
386
+ // Infrastructure errors (unexpected)
387
+ class DatabaseConnectionError extends InfrastructureException {}
388
+
389
+ // Presentation: map to HTTP status
390
+ function errorHandler(error: Error): Response {
391
+ if (error instanceof DomainException) return { status: 400 }
392
+ if (error instanceof InfrastructureException) return { status: 500 }
393
+ }
394
+
395
+ deliverables:
396
+ - id: DL-STRUCTURE
397
+ rule: "4-layer folder structure enforced per code-type convention"
398
+ reference: "See frontend.convention.yaml or backend.convention.yaml for specific component types and file suffixes"
399
+
400
+ - id: DL-PORTS
401
+ rule: "Port interfaces in application/; adapters in integration/"
402
+ verification:
403
+ - "Every port has at least one implementation"
404
+ - "Implementations injected via DI/factory"
405
+ - "Tests can swap implementations easily"
406
+
407
+ - id: DL-GUARDS
408
+ rule: "Architecture guardrails active in CI"
409
+ examples:
410
+ - "ESLint rules block forbidden imports"
411
+ - "CI fails if domain imports application"
412
+ - "ArchUnit tests verify layer boundaries"
413
+ checks:
414
+ - type: import_scan
415
+ forbid:
416
+ - "domain → application|presentation|integration"
417
+ - "application → presentation|integration"
418
+ - "presentation → integration"
419
+
420
+ - id: DL-TESTS
421
+ rule: "Internal unit tests for Domain & Application; acceptance tests still green"
422
+ targets:
423
+ domain_coverage: ">=90%"
424
+ application_coverage: ">=80%"
425
+ integration_coverage: ">=70%"
426
+ note: "Presentation layer covered by acceptance tests"
427
+
428
+ - id: DL-LOG
429
+ rule: "Short log documenting moves and remaining debt"
430
+ template: |
431
+ ## Refactoring Summary
432
+
433
+ ### Extracted to Domain
434
+ - Order entity with validation
435
+ - Money value object
436
+ - OrderPolicy business rules
437
+
438
+ ### Created Use Cases
439
+ - CreateOrderUseCase
440
+ - CancelOrderUseCase
441
+
442
+ ### Ports Defined
443
+ - OrderRepository (implemented by PostgresOrderRepo)
444
+ - PaymentGateway (implemented by StripePaymentGateway)
445
+
446
+ ### Remaining Tech Debt
447
+ - TODO: Add caching layer for frequent queries
448
+ - TODO: Implement outbox pattern for event publishing
449
+ - TODO: Add circuit breaker to payment gateway
450
+
451
+ done_criteria:
452
+ - id: DC-TESTS
453
+ requirement: "All acceptance tests still pass (no behavior change)"
454
+ - id: DC-ARCH
455
+ requirement: "Layers compile without upward leaks (no infra import in domain/app)"
456
+ - id: DC-COMPLEXITY
457
+ requirement: "Cyclomatic complexity and duplication reduced"
458
+ - id: DC-SEAMS
459
+ requirement: "Clear seams for future changes"
460
+ - id: DC-MAINT
461
+ requirement: "New features can be added with minimal changes"
462
+
463
+ anti_patterns:
464
+ - id: AP-LEAK
465
+ text: "Leaky abstractions"
466
+ avoid: "Domain/application importing integration types"
467
+ example: "Order entity importing PostgreSQL types"
468
+ fix: "Use mappers in integration layer"
469
+
470
+ - id: AP-ANEMIC
471
+ text: "Anemic domain model"
472
+ avoid: "Entities with only getters/setters; all logic in services"
473
+ fix: "Move business rules into entity methods"
474
+
475
+ - id: AP-FATUC
476
+ text: "Fat use cases"
477
+ avoid: "Use cases with complex business logic"
478
+ fix: "Extract domain services or move logic to entities"
479
+
480
+ - id: AP-SKIPPORTS
481
+ text: "Skipping ports pattern"
482
+ avoid: "Presentation calling integration directly"
483
+ fix: "Always route through application use cases"
484
+
485
+ - id: AP-OVERENG
486
+ text: "Over-engineering"
487
+ avoid: "Adding patterns before they're needed"
488
+ fix: "Wait for 3rd occurrence before abstracting"
489
+
490
+ quality_metrics:
491
+ - id: QM-ARCH
492
+ metrics:
493
+ - "Zero forbidden imports detected"
494
+ - "All ports have adapters"
495
+ - "Domain layer has zero external dependencies"
496
+ checks:
497
+ - type: import_scan
498
+ report: "forbidden_edges_count"
499
+
500
+ - id: QM-COMPLEXITY
501
+ metrics:
502
+ - "Average cyclomatic complexity < 5"
503
+ - "Max function length < 30 lines"
504
+ - "Max class length < 200 lines"
505
+
506
+ - id: QM-DUP
507
+ metrics:
508
+ - "< 5% code duplication"
509
+ - "Similar logic extracted to shared helpers"
510
+
511
+ - id: QM-TEST
512
+ metrics:
513
+ - "Domain: 100% testable without infrastructure"
514
+ - "Application: 100% testable with mocked ports"
515
+ - "Integration: Testable with test containers/fakes"
516
+
517
+ ci_gates:
518
+ description: "Automated enforcement in CI pipeline"
519
+ on: "pull_request"
520
+ require:
521
+ - "acceptance: green"
522
+ - DL-GUARDS
523
+ - QM-ARCH
524
+ thresholds:
525
+ complexity: "avg < 5"
526
+ coverage_domain: ">=90%"
527
+ coverage_application: ">=80%"
528
+
529
+ handoff_criteria:
530
+ description: "Ready for next feature when all criteria met"
531
+ checklist:
532
+ - "All GREEN TODOs addressed"
533
+ - "Boundary tests passing"
534
+ - "Refactor log committed"
535
+ - "Ready for next feature"