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,587 @@
1
+ version: "1.0"
2
+ name: "Presentation Convention"
3
+ description: "Presentation layer implementation patterns across Python, TypeScript, and Dart"
4
+
5
+ purpose: |
6
+ Defines how to implement presentation layer (HTTP REST, CLI, GraphQL) across runtimes.
7
+
8
+ Presentation layer translates external protocols (HTTP, CLI args) to domain operations
9
+ and formats domain artifacts back to external representations (JSON responses, terminal output).
10
+
11
+ Key principle: Presentation is THIN - all business logic stays in domain/application layers.
12
+
13
+ relationship:
14
+ component_types: "backend.convention.yaml (defines controller/route/serializer types)"
15
+ phase_guidance: "green.convention.yaml (when to create, GREEN simplifications)"
16
+ contract_alignment: "dto.convention.yaml (DTOs as API response models)"
17
+ architecture: "design.convention.yaml (dependency flow: presentation → application → domain)"
18
+
19
+ architecture:
20
+ layers:
21
+ presentation:
22
+ what: "External interface adapters (HTTP, CLI, GraphQL)"
23
+ location: "{wagon}/{feature}/src/presentation/"
24
+ authority: "presentation.convention.yaml (this file)"
25
+ owner: "coder agent"
26
+
27
+ application:
28
+ what: "Use cases orchestrating domain operations"
29
+ location: "{wagon}/{feature}/src/application/"
30
+ note: "Presentation calls application use cases, never domain directly"
31
+
32
+ contract_dto:
33
+ what: "Response models aligned with contract schemas"
34
+ location: "python/contracts/, dart/lib/contracts/"
35
+ note: "Pydantic/Freezed models matching JSON schemas"
36
+
37
+ flow: |
38
+ HTTP Request → Controller → Use Case → Domain
39
+
40
+ JSON Response ← Response Model ← Artifact ← Domain
41
+
42
+ # ============================================================================
43
+ # HTTP REST API PATTERNS
44
+ # ============================================================================
45
+
46
+ http_rest_api:
47
+ description: "REST API implementation patterns across runtimes"
48
+
49
+ when_to_use:
50
+ - "Wagon produces artifacts (100% of wagons in contract-driven architecture)"
51
+ - "Artifact has contract schema that needs validation"
52
+ - "Manual testing via Swagger UI (faster than writing pytest)"
53
+ - "Game server/mobile app needs HTTP endpoint to consume artifact"
54
+ - "Cross-team testing without Python/runtime setup"
55
+ - "Debugging requires inspecting artifact JSON in browser"
56
+
57
+ rationale: |
58
+ We are CONTRACT-DRIVEN. Every wagon produces artifacts with schemas.
59
+
60
+ Pattern: Wagon → Domain → Artifact → Presentation (HTTP) → JSON Response
61
+
62
+ Benefits:
63
+ - Swagger UI validates contract alignment automatically
64
+ - Pydantic models enforce schema at runtime
65
+ - Developers test via browser, not pytest
66
+ - Game server integrates via REST, not Python imports
67
+ - QA tests without local Python setup
68
+
69
+ when_not_to_use:
70
+ - "Wagon produces no artifacts (0% of current wagons)"
71
+ - "Pure library code with no outputs (e.g., shared crypto utils)"
72
+
73
+ # --------------------------------------------------------------------------
74
+ # PYTHON FASTAPI
75
+ # --------------------------------------------------------------------------
76
+
77
+ python_fastapi:
78
+ version_support: "FastAPI 0.100+, Pydantic 2.0+, uvicorn"
79
+
80
+ file_structure:
81
+ controller: "python/{wagon}/{feature}/src/presentation/controllers/{feature}_controller.py"
82
+ response_models: "Pydantic models in same controller file (GREEN) or separate models.py (REFACTOR)"
83
+ urn_marker: "# urn: component:{wagon}:{feature}.{Feature}Controller.backend.presentation"
84
+
85
+ pattern:
86
+ description: "FastAPI app with Pydantic models aligned to contract schemas"
87
+
88
+ minimal_example: |
89
+ # urn: component:burn-timebank:track-remaining.RemainingController.backend.presentation
90
+ # Runtime: python
91
+ # Purpose: HTTP REST endpoint for timebank remaining
92
+
93
+ """
94
+ RemainingController - FastAPI REST endpoint.
95
+
96
+ Contract: mechanic:timebank.remaining
97
+ """
98
+ from fastapi import FastAPI, Query
99
+ from pydantic import BaseModel, Field
100
+ from typing import Optional
101
+
102
+ # Import domain/application layers using QUALIFIED imports
103
+ import sys
104
+ from pathlib import Path
105
+ sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent.parent))
106
+
107
+ from burn_timebank.track_remaining.src.domain.entities.timebank import Timebank
108
+
109
+
110
+ # Pydantic response model matching contract schema
111
+ class TimebankRemainingResponse(BaseModel):
112
+ """
113
+ Response model for mechanic:timebank.remaining artifact.
114
+
115
+ Contract: contracts/mechanic/timebank/remaining.schema.json
116
+ """
117
+ remaining_seconds: float = Field(
118
+ ...,
119
+ description="Time remaining in seconds",
120
+ example=180.0
121
+ )
122
+ is_low: bool = Field(
123
+ ...,
124
+ description="Whether time is below warning threshold",
125
+ example=False
126
+ )
127
+ preset: Optional[str] = Field(
128
+ None,
129
+ description="Time control preset",
130
+ example="blitz"
131
+ )
132
+ artifact_name: str = Field(
133
+ default="mechanic:timebank.remaining",
134
+ description="Artifact identifier"
135
+ )
136
+
137
+
138
+ # FastAPI application
139
+ app = FastAPI(
140
+ title="Burn Timebank API",
141
+ description="Track remaining time with low-time warnings",
142
+ version="0.1.0",
143
+ docs_url="/docs",
144
+ redoc_url="/redoc",
145
+ )
146
+
147
+
148
+ # GREEN: Simple global state
149
+ # TODO(REFACTOR): Use Redis/database for state management
150
+ _timebank_instance: Optional[Timebank] = None
151
+
152
+
153
+ @app.get(
154
+ "/timebank/remaining",
155
+ response_model=TimebankRemainingResponse,
156
+ summary="Get remaining timebank",
157
+ tags=["timebank"],
158
+ )
159
+ def get_remaining(
160
+ initial_seconds: Optional[float] = Query(None, example=180.0)
161
+ ) -> TimebankRemainingResponse:
162
+ """
163
+ Get current timebank state.
164
+
165
+ Contract: mechanic:timebank.remaining
166
+ """
167
+ global _timebank_instance
168
+
169
+ # GREEN: Initialize if needed
170
+ if _timebank_instance is None or initial_seconds is not None:
171
+ _timebank_instance = Timebank(
172
+ initial_seconds=initial_seconds or 180.0,
173
+ preset="blitz"
174
+ )
175
+
176
+ # Call domain layer
177
+ artifact = _timebank_instance.emit_remaining()
178
+
179
+ # Map domain artifact to response model
180
+ return TimebankRemainingResponse(
181
+ remaining_seconds=artifact.remaining_seconds,
182
+ is_low=artifact.is_low,
183
+ preset=artifact.preset,
184
+ artifact_name=artifact.artifact_name
185
+ )
186
+
187
+
188
+ @app.post(
189
+ "/timebank/tick",
190
+ response_model=TimebankRemainingResponse,
191
+ summary="Decrement timebank",
192
+ tags=["timebank"],
193
+ )
194
+ def tick_timebank(
195
+ elapsed_seconds: float = Query(..., example=10.0)
196
+ ) -> TimebankRemainingResponse:
197
+ """Simulate time passage."""
198
+ global _timebank_instance
199
+
200
+ if _timebank_instance is None:
201
+ _timebank_instance = Timebank(180.0, "blitz")
202
+
203
+ # Call domain mutation
204
+ _timebank_instance.tick(elapsed_seconds=elapsed_seconds)
205
+
206
+ # Return updated state
207
+ artifact = _timebank_instance.emit_remaining()
208
+ return TimebankRemainingResponse(
209
+ remaining_seconds=artifact.remaining_seconds,
210
+ is_low=artifact.is_low,
211
+ preset=artifact.preset,
212
+ artifact_name=artifact.artifact_name
213
+ )
214
+
215
+ composition_integration:
216
+ description: "Dual-mode composition.py supporting CLI and HTTP"
217
+
218
+ pattern: |
219
+ # composition.py supports both modes
220
+ def main(mode: str = "cli"):
221
+ """
222
+ Bootstrap application in CLI or HTTP mode.
223
+
224
+ Args:
225
+ mode: "cli" for terminal demo, "http" for FastAPI server
226
+ """
227
+ # Wire dependencies
228
+ timebank = Timebank(initial_seconds=180.0, preset="blitz")
229
+
230
+ if mode == "cli":
231
+ # CLI mode: Terminal demo
232
+ print("📊 Demo: Simulating time passage...")
233
+ for i in range(3):
234
+ timebank.tick(elapsed_seconds=10.0)
235
+ artifact = timebank.emit_remaining()
236
+ print(f"Tick {i+1}: {artifact.remaining_seconds}s")
237
+
238
+ return timebank
239
+
240
+ elif mode == "http":
241
+ # HTTP mode: FastAPI server
242
+ from src.presentation.controllers.feature_controller import app, _set_timebank
243
+ import uvicorn
244
+
245
+ # Initialize app with wired dependencies
246
+ _set_timebank(timebank)
247
+
248
+ print("🚀 Starting FastAPI server...")
249
+ print("📖 Swagger UI: http://127.0.0.1:8000/docs")
250
+ print("🔗 API: http://127.0.0.1:8000/resource")
251
+
252
+ # Run server
253
+ uvicorn.run(app, host="127.0.0.1", port=8000, reload=False)
254
+ return app
255
+
256
+ if __name__ == "__main__":
257
+ import argparse
258
+ parser = argparse.ArgumentParser()
259
+ parser.add_argument("--mode", choices=["cli", "http"], default="cli")
260
+ args = parser.parse_args()
261
+ main(mode=args.mode)
262
+
263
+ usage:
264
+ cli_demo: "python3 python/{wagon}/{feature}/composition.py"
265
+ http_server: "python3 python/{wagon}/{feature}/composition.py --mode http"
266
+ swagger_ui: "Open http://127.0.0.1:8000/docs for interactive testing"
267
+
268
+ contract_alignment:
269
+ principle: "Pydantic models MUST match contract JSON schemas field-for-field"
270
+
271
+ validation:
272
+ - "Response model fields match contract artifact schema"
273
+ - "Field types match JSON schema types (string→str, number→float, boolean→bool)"
274
+ - "Required fields marked with ..."
275
+ - "Optional fields marked with Optional[T]"
276
+ - "Default values match contract defaults"
277
+
278
+ example_mapping: |
279
+ # Contract schema: contracts/mechanic/timebank/remaining.schema.json
280
+ {
281
+ "remaining_seconds": {"type": "number", "description": "..."},
282
+ "is_low": {"type": "boolean"},
283
+ "preset": {"type": "string", "enum": ["blitz", "rapid", "classical"]},
284
+ "artifact_name": {"type": "string", "default": "mechanic:timebank.remaining"}
285
+ }
286
+
287
+ # Pydantic model (MUST match)
288
+ class TimebankRemainingResponse(BaseModel):
289
+ remaining_seconds: float = Field(..., description="...")
290
+ is_low: bool
291
+ preset: Optional[str]
292
+ artifact_name: str = Field(default="mechanic:timebank.remaining")
293
+
294
+ green_phase_simplifications:
295
+ description: "Acceptable shortcuts in GREEN phase with TODO markers for REFACTOR"
296
+
297
+ allowed:
298
+ state_management:
299
+ green: "Global variable: _instance = None"
300
+ refactor: "TODO(REFACTOR): Use Redis/database for state management"
301
+
302
+ authentication:
303
+ green: "Skip authentication in GREEN"
304
+ refactor: "TODO(REFACTOR): Add JWT authentication with FastAPI Depends"
305
+
306
+ error_handling:
307
+ green: "Basic try/except with 500 responses"
308
+ refactor: "TODO(REFACTOR): Add custom exception handlers and status codes"
309
+
310
+ validation:
311
+ green: "Pydantic validates input automatically"
312
+ refactor: "TODO(REFACTOR): Add domain-level business rule validation"
313
+
314
+ cors:
315
+ green: "Allow all origins: CORSMiddleware(allow_origins=['*'])"
316
+ refactor: "TODO(REFACTOR): Configure proper CORS for production"
317
+
318
+ swagger_ui:
319
+ description: "Auto-generated interactive API documentation"
320
+
321
+ benefits:
322
+ - "Instant manual testing without writing test code"
323
+ - "Interactive request builder with example values"
324
+ - "Response schema visualization"
325
+ - "Contract validation via example requests"
326
+ - "Stakeholder demos without separate frontend"
327
+
328
+ customization: |
329
+ app = FastAPI(
330
+ title="{Wagon} API",
331
+ description="...",
332
+ version="0.1.0",
333
+ docs_url="/docs", # Swagger UI
334
+ redoc_url="/redoc", # ReDoc alternative
335
+ openapi_url="/openapi.json" # OpenAPI schema
336
+ )
337
+
338
+ api_tagging:
339
+ rule: "All endpoints MUST use wagon name in Title Case as single tag"
340
+ pattern: 'tags=["{Wagon Name}"]'
341
+
342
+ examples:
343
+ - 'burn_timebank → "Burn Timebank"'
344
+ - 'play_match → "Play Match"'
345
+ - 'juggle_domains → "Juggle Domains"'
346
+
347
+ anti_patterns:
348
+ - '"match-lifecycle" (kebab-case, not wagon name)'
349
+ - '"Impact Domains" (incorrect wagon name)'
350
+ - 'Multiple tags per wagon ("Burn Time", "Handle Timeout")'
351
+
352
+ rationale: "Wagon-based grouping aligns with domain boundaries and provides clear ownership in Swagger UI"
353
+
354
+ reference_implementation:
355
+ file: "python/burn_timebank/track_remaining/src/presentation/controllers/remaining_controller.py"
356
+ composition: "python/burn_timebank/track_remaining/composition.py"
357
+ note: "Study this as the canonical example"
358
+
359
+ # --------------------------------------------------------------------------
360
+ # TYPESCRIPT SUPABASE EDGE FUNCTIONS
361
+ # --------------------------------------------------------------------------
362
+
363
+ typescript_supabase:
364
+ version_support: "Deno 1.30+, Supabase Edge Functions"
365
+
366
+ file_structure:
367
+ handler: "supabase/functions/{wagon}/{feature}/index.ts"
368
+ types: "supabase/functions/{wagon}/{feature}/types.ts (if needed)"
369
+ urn_marker: "// urn: component:{wagon}:{feature}.handler.backend.presentation"
370
+
371
+ pattern:
372
+ description: "Thin edge function handler calling domain logic"
373
+
374
+ minimal_example: |
375
+ // urn: component:authenticate-identity:validate-credentials.handler.backend.presentation
376
+ // Runtime: supabase
377
+ // Purpose: HTTP endpoint for credential validation
378
+
379
+ /**
380
+ * ValidateCredentialsHandler - Supabase Edge Function
381
+ *
382
+ * Contract: identity:credentials.validation
383
+ */
384
+ import { serve } from "https://deno.land/std@0.168.0/http/server.ts"
385
+ import { corsHeaders } from "../_shared/cors.ts"
386
+
387
+ // Type matching contract schema
388
+ interface ValidationRequest {
389
+ username: string
390
+ password: string
391
+ }
392
+
393
+ interface ValidationResponse {
394
+ valid: boolean
395
+ user_id?: string
396
+ artifact_name: string
397
+ }
398
+
399
+ serve(async (req: Request) => {
400
+ // CORS preflight
401
+ if (req.method === "OPTIONS") {
402
+ return new Response("ok", { headers: corsHeaders })
403
+ }
404
+
405
+ try {
406
+ // Parse request
407
+ const body: ValidationRequest = await req.json()
408
+
409
+ // GREEN: Simple validation logic
410
+ // TODO(REFACTOR): Call domain service via use case
411
+ const valid = body.username.length > 0 && body.password.length >= 8
412
+
413
+ // Build response matching contract
414
+ const response: ValidationResponse = {
415
+ valid,
416
+ user_id: valid ? "user-123" : undefined,
417
+ artifact_name: "identity:credentials.validation"
418
+ }
419
+
420
+ return new Response(
421
+ JSON.stringify(response),
422
+ {
423
+ headers: {
424
+ ...corsHeaders,
425
+ "Content-Type": "application/json"
426
+ },
427
+ status: 200
428
+ }
429
+ )
430
+
431
+ } catch (error) {
432
+ return new Response(
433
+ JSON.stringify({ error: error.message }),
434
+ {
435
+ headers: { ...corsHeaders, "Content-Type": "application/json" },
436
+ status: 500
437
+ }
438
+ )
439
+ }
440
+ })
441
+
442
+ green_simplifications:
443
+ allowed:
444
+ - "Inline validation logic (move to domain in REFACTOR)"
445
+ - "Simple error handling (enhance in REFACTOR)"
446
+ - "Allow all CORS origins (restrict in REFACTOR)"
447
+ - "No authentication (add Supabase Auth in REFACTOR)"
448
+
449
+ reference:
450
+ note: "Supabase functions are THIN by design - keep logic in Python backend"
451
+
452
+ # ============================================================================
453
+ # CLI PATTERNS
454
+ # ============================================================================
455
+
456
+ cli_pattern:
457
+ description: "Command-line interface patterns for feature demos and testing"
458
+
459
+ python_argparse:
460
+ pattern: |
461
+ # composition.py with CLI argument parsing
462
+ import argparse
463
+
464
+ def main():
465
+ parser = argparse.ArgumentParser(
466
+ description="{Feature} - {description}"
467
+ )
468
+ parser.add_argument("param", type=float, help="...")
469
+ parser.add_argument("--preset", choices=["a", "b"], default="a")
470
+ parser.add_argument("--verbose", action="store_true")
471
+
472
+ args = parser.parse_args()
473
+
474
+ # Wire dependencies and run
475
+ entity = DomainEntity(args.param)
476
+ result = entity.execute()
477
+
478
+ # Format output
479
+ print(f"Result: {result}")
480
+
481
+ rich_output:
482
+ description: "Enhanced terminal output per refactor.convention.yaml"
483
+
484
+ patterns:
485
+ colors:
486
+ green: "✅ Success indicators"
487
+ yellow: "⚠️ Warning states"
488
+ red: "❌ Error states"
489
+ cyan: "ℹ️ Info messages"
490
+
491
+ progress_bars:
492
+ pattern: "[████████░░░░] 80.0% (80/100)"
493
+ usage: "Time depletion, resource consumption"
494
+
495
+ animations:
496
+ dots: "Processing... (animated dots)"
497
+ delays: "Small delays (0.3s) for realism"
498
+
499
+ structure:
500
+ sections: "Clear headers with ======="
501
+ indentation: "Hierarchical output structure"
502
+ summaries: "Final summary tables"
503
+
504
+ reference_implementation:
505
+ file: "python/burn_timebank/wagon.py"
506
+ note: "Rich CLI feedback with colors, progress bars, delays"
507
+
508
+ # ============================================================================
509
+ # VALIDATION
510
+ # ============================================================================
511
+
512
+ validation:
513
+ description: "Automated checks for presentation layer compliance"
514
+
515
+ validator_location: "atdd/coder/validate_presentation.py"
516
+
517
+ checks:
518
+ fastapi_controller:
519
+ - "File has URN marker: # urn: component:{wagon}:{feature}.{Name}Controller.backend.presentation"
520
+ - "Imports FastAPI and Pydantic"
521
+ - "Defines Pydantic response model with Field(...) descriptors"
522
+ - "Response model has artifact_name field"
523
+ - "Has @app.get or @app.post decorators"
524
+ - "Endpoints have summary and tags"
525
+
526
+ contract_alignment:
527
+ - "Pydantic model fields match contract schema fields"
528
+ - "Field types match (number→float, boolean→bool)"
529
+ - "Required fields marked with ..."
530
+ - "Optional fields marked with Optional[T]"
531
+
532
+ composition_integration:
533
+ - "composition.py has mode parameter ('cli' or 'http')"
534
+ - "HTTP mode imports controller and calls uvicorn.run"
535
+ - "CLI mode runs domain demo without HTTP"
536
+
537
+ green_simplifications:
538
+ - "Global state variables have TODO(REFACTOR) comments"
539
+ - "Missing auth has TODO(REFACTOR) marker"
540
+ - "Simple error handling has TODO(REFACTOR) marker"
541
+
542
+ unified_game_server:
543
+ description: "python/game.py must aggregate all wagon presentation layers"
544
+ file: "python/game.py"
545
+ requirements:
546
+ - "When new wagon adds FastAPI controller, game.py MUST be updated"
547
+ - "game.py imports controller's app and includes via app.include_router()"
548
+ - "All wagon endpoints accessible via unified game server"
549
+ - "Validator checks: all wagons with presentation are registered in game.py"
550
+
551
+ rationale: |
552
+ game.py is the unified entry point for all backend services.
553
+ Without registration, wagon endpoints are inaccessible to game server/mobile app.
554
+
555
+ pattern: |
556
+ # python/game.py
557
+ from burn_timebank.track_remaining.src.presentation.controllers.remaining_controller import app as timebank_app
558
+ app.include_router(timebank_app.router, prefix="/timebank")
559
+
560
+ anti_pattern: |
561
+ # ❌ WRONG: Wagon has FastAPI controller but not registered in game.py
562
+ # Result: Endpoints exist but unreachable from unified server
563
+
564
+ usage: |
565
+ python3 atdd/coder/test_presentation_convention.py
566
+ python3 atdd/coder/test_presentation_convention.py --check-game-server
567
+
568
+ # ============================================================================
569
+ # CROSS-REFERENCES
570
+ # ============================================================================
571
+
572
+ cross_references:
573
+ component_types: "backend.convention.yaml::presentation (controller/route/serializer types)"
574
+ phase_guidance: "green.convention.yaml::composition_root (when to create)"
575
+ contract_dto: "dto.convention.yaml (Pydantic/Freezed models)"
576
+ architecture: "design.convention.yaml (Clean Architecture dependency flow)"
577
+ rich_cli: "refactor.convention.yaml::rich_cli_feedback (colors, progress bars)"
578
+ boundaries: "boundaries.convention.yaml (qualified imports)"
579
+
580
+ examples:
581
+ python_fastapi:
582
+ full: "python/burn_timebank/track_remaining/src/presentation/controllers/remaining_controller.py"
583
+ composition: "python/burn_timebank/track_remaining/composition.py"
584
+
585
+ cli_rich:
586
+ wagon: "python/burn_timebank/wagon.py"
587
+ note: "Rich output with colors, progress bars, delays"