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,509 @@
1
+ version: "1.1"
2
+ name: "Contract-Driven Migration Convention"
3
+ description: "Generate Supabase PostgreSQL migrations from contract JSON schemas and infrastructure tables"
4
+
5
+ # Workflow Integration
6
+ workflow:
7
+ trigger: "After contract generation by tester"
8
+
9
+ phases:
10
+ 1_scan: "Identify contracts without corresponding migrations"
11
+ 2_generate: "Create migration template with TODO markers"
12
+ 3_validate: "Ensure all contracts have migrations (ATDD test)"
13
+ 4_review: "Human completes TODOs (foreign keys, indexes, RLS)"
14
+ 5_apply: "supabase db push"
15
+
16
+ automation_level: "template_generation"
17
+ requires_human_review: true
18
+
19
+ command: "python atdd/coach/command/migration.py"
20
+
21
+ # Table Naming Convention
22
+ table_naming:
23
+ pattern: "{theme}_{domain}_{aspect}"
24
+ description: "Derives from contract x-artifact-metadata and file path"
25
+
26
+ examples:
27
+ - contract: "contracts/match/dilemma/current.schema.json"
28
+ metadata: "{domain: 'dilemma', resource: 'current'}"
29
+ path_theme: "match"
30
+ table_name: "match_dilemma_current"
31
+
32
+ - contract: "contracts/commons/ux/foundations.schema.json"
33
+ metadata: "{domain: 'ux', resource: 'foundations'}"
34
+ path_theme: "commons"
35
+ table_name: "commons_ux_foundations"
36
+
37
+ normalization: "snake_case"
38
+ max_length: 63 # PostgreSQL limit
39
+
40
+ # Type Mapping: JSON Schema → PostgreSQL
41
+ type_mapping:
42
+ primitives:
43
+ string:
44
+ default: "TEXT"
45
+ with_pattern_uuid: "UUID"
46
+ with_format_date_time: "TIMESTAMPTZ"
47
+ with_format_date: "DATE"
48
+ with_format_time: "TIME"
49
+ with_format_email: "TEXT" # Consider VARCHAR(255) for indexing
50
+ with_format_uri: "TEXT"
51
+
52
+ integer: "INTEGER"
53
+ number: "NUMERIC"
54
+ boolean: "BOOLEAN"
55
+
56
+ complex:
57
+ object: "JSONB" # Flag for normalization review
58
+ array: "JSONB" # Flag for normalization review
59
+
60
+ special_cases:
61
+ enum: "TEXT" # Add CHECK constraint
62
+ const: "TEXT" # Add CHECK constraint with value
63
+
64
+ notes:
65
+ - "JSONB for complex types requires TODO marker to consider normalization"
66
+ - "UUID pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
67
+ - "Enums generate CHECK constraints: CHECK (column IN ('val1', 'val2'))"
68
+
69
+ # Migration Template Structure
70
+ template_structure:
71
+ header:
72
+ - "-- Generated from {contract_path}"
73
+ - "-- Generation time: {timestamp}"
74
+ - "-- ⚠️ REVIEW REQUIRED BEFORE APPLYING"
75
+ - ""
76
+
77
+ table_definition:
78
+ primary_key: "id UUID PRIMARY KEY DEFAULT gen_random_uuid()"
79
+ columns: "Derived from contract properties"
80
+ constraints: "NOT NULL for required fields, CHECK for patterns"
81
+
82
+ standard_columns:
83
+ - "created_at TIMESTAMPTZ DEFAULT NOW()"
84
+ - "updated_at TIMESTAMPTZ DEFAULT NOW()"
85
+
86
+ todo_markers:
87
+ - "-- ⚠️ TODO: Add foreign key constraints"
88
+ - "-- ⚠️ TODO: Add indexes for common queries"
89
+ - "-- ⚠️ TODO: Add RLS policies"
90
+ - "-- ⚠️ TODO: Add trigger for updated_at"
91
+ - "-- ⚠️ TODO: Review JSONB columns for normalization"
92
+
93
+ footer:
94
+ - "-- End of migration"
95
+
96
+ # Required TODOs for Human Review
97
+ human_review_required:
98
+ foreign_keys:
99
+ description: "Identify relationships between tables"
100
+ example: "ALTER TABLE match_dilemma_current ADD CONSTRAINT fk_fragment_a FOREIGN KEY (fragment_a_id) REFERENCES fragments(id);"
101
+ rationale: "Contract doesn't define referential integrity"
102
+
103
+ indexes:
104
+ description: "Add indexes for query performance"
105
+ example: "CREATE INDEX idx_dilemma_created ON match_dilemma_current(created_at DESC);"
106
+ rationale: "Access patterns unknown at generation time"
107
+
108
+ rls_policies:
109
+ description: "Row-level security for multi-tenant isolation"
110
+ example: "CREATE POLICY 'users_own_data' ON match_dilemma_current FOR SELECT USING (auth.uid() = user_id);"
111
+ rationale: "Security requirements specific to application"
112
+
113
+ triggers:
114
+ description: "Lifecycle hooks like updated_at timestamps"
115
+ example: "CREATE TRIGGER set_updated_at BEFORE UPDATE ON match_dilemma_current FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();"
116
+ rationale: "Automation preferences vary"
117
+
118
+ normalization:
119
+ description: "Extract nested objects to separate tables"
120
+ example: "Instead of JSONB, create separate fragments table"
121
+ rationale: "Schema design requires domain knowledge"
122
+
123
+ # Validation Rules
124
+ validation:
125
+ coverage:
126
+ rule: "Every contract must have migration or existing table"
127
+ test: "atdd/tester/test_migration_coverage.py::test_all_contracts_have_migrations"
128
+ failure: "Lists contracts without migrations"
129
+
130
+ no_unreviewed_todos:
131
+ rule: "Migrations cannot be applied with TODO markers"
132
+ test: "atdd/tester/test_migration_coverage.py::test_migration_templates_reviewed"
133
+ failure: "Lists migrations with unresolved TODOs"
134
+
135
+ type_mapping_complete:
136
+ rule: "All JSON Schema types must map to PostgreSQL"
137
+ test: "atdd/tester/test_migration_generation.py::test_json_to_postgres_type_mapping"
138
+ failure: "Reports unmapped types"
139
+
140
+ # Output Paths
141
+ output:
142
+ migrations_directory: "supabase/migrations/"
143
+ filename_pattern: "{timestamp}_{theme}_{domain}_{aspect}.sql"
144
+ timestamp_format: "%Y%m%d%H%M%S"
145
+
146
+ example: "supabase/migrations/20251030143000_match_dilemma_current.sql"
147
+
148
+ # Integration with ATDD Workflow
149
+ atdd_integration:
150
+ phase: "tester"
151
+ trigger: "After contract generation"
152
+
153
+ steps:
154
+ 1: "Generate contract from wagon interface"
155
+ 2: "Generate migration template from contract"
156
+ 3: "Run coverage validation (RED if missing)"
157
+ 4: "Human reviews and completes TODOs"
158
+ 5: "Run validation (GREEN when complete)"
159
+ 6: "Apply migration: supabase db push"
160
+
161
+ tests:
162
+ generation: "atdd/tester/test_migration_generation.py"
163
+ coverage: "atdd/tester/test_migration_coverage.py"
164
+
165
+ # References
166
+ references:
167
+ contract_convention: ".claude/conventions/tester/contract.convention.yaml"
168
+ supabase_docs: "https://supabase.com/docs/guides/database/tables"
169
+ postgres_types: "https://www.postgresql.org/docs/current/datatype.html"
170
+
171
+ # Command Usage
172
+ usage: |
173
+ # Generate all missing migrations
174
+ python atdd/coach/command/migration.py
175
+
176
+ # Generate for specific contract
177
+ python atdd/coach/command/migration.py --contract contracts/match/dilemma/current.schema.json
178
+
179
+ # Validate coverage
180
+ python atdd/coach/command/migration.py --validate
181
+
182
+ # Check for unreviewed TODOs
183
+ pytest atdd/tester/test_migration_coverage.py::test_migration_templates_reviewed
184
+
185
+ # JSONB-First Storage Strategy
186
+ jsonb_strategy:
187
+ pattern: "JSONB blob storage for document-like wagon contracts"
188
+ rationale: |
189
+ Wagon architecture treats contracts as atomic documents consumed by wagons.
190
+ JSONB blob storage aligns with this pattern:
191
+ - Wagons process complete contracts, not normalized fields
192
+ - Contract validation happens at application layer (JSON Schema)
193
+ - No SQL joins needed (references resolved via URNs in application)
194
+ - Event-driven: hot path is in-memory, DB is persistence layer
195
+ - Bounded contexts: each entity lives in its lifecycle (match/session/scenario)
196
+
197
+ standard_table_structure: |
198
+ CREATE TABLE {theme}_{domain}_{aspect} (
199
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
200
+ data JSONB NOT NULL,
201
+ created_at TIMESTAMPTZ DEFAULT NOW(),
202
+ updated_at TIMESTAMPTZ DEFAULT NOW()
203
+ );
204
+ CREATE INDEX idx_{table}_data ON {table} USING GIN (data);
205
+
206
+ migrations_not_needed:
207
+ description: "Contract schema changes do NOT trigger database migrations"
208
+ scenarios:
209
+ - change: "Add optional field to contract"
210
+ migration: "❌ Not needed"
211
+ reason: "Old records lack field, app provides default"
212
+ - change: "Remove field from contract"
213
+ migration: "❌ Not needed"
214
+ reason: "Old records keep field in JSONB (ignored by app)"
215
+ - change: "Change field type (string → int)"
216
+ migration: "❌ Not needed"
217
+ reason: "App handles both formats via _version field"
218
+ - change: "Rename field"
219
+ migration: "❌ Not needed (but code complexity)"
220
+ reason: "App reads old and new field names during transition"
221
+
222
+ migrations_needed:
223
+ description: "Only structural changes require database migrations"
224
+ scenarios:
225
+ - change: "New contract introduced"
226
+ migration: "✅ CREATE TABLE"
227
+ tool: "migration.py from contract schema"
228
+ - change: "Contract retired/deleted"
229
+ migration: "✅ DROP TABLE (optional)"
230
+ tool: "Manual via Supabase CLI"
231
+ - change: "Add index for discovered query pattern"
232
+ migration: "✅ CREATE INDEX"
233
+ tool: "Supabase CLI: supabase db diff"
234
+ - change: "Extract column for performance"
235
+ migration: "✅ ALTER TABLE ADD COLUMN"
236
+ tool: "Manual optimization (rare)"
237
+
238
+ versioning:
239
+ description: "Dual versioning strategy for schema evolution"
240
+
241
+ schema_version:
242
+ location: "contracts/{theme}/{domain}/{aspect}.schema.json"
243
+ field: "version"
244
+ format: "Semantic versioning (1.0.0, 1.1.0, 2.0.0)"
245
+ purpose: "Documents contract schema definition version"
246
+ used_by: "Developers, validators, documentation"
247
+ example: |
248
+ {
249
+ "$id": "match:dilemma:current",
250
+ "version": "2.0.0", ← Contract schema is at v2.0.0
251
+ "properties": { ... }
252
+ }
253
+
254
+ data_version:
255
+ location: "Database JSONB data blob"
256
+ field: "_version"
257
+ format: "String major version (\"1\", \"2\")"
258
+ purpose: "Tags which schema version this specific data conforms to"
259
+ used_by: "Application runtime code for backward compatibility"
260
+ example: |
261
+ // Data in Supabase JSONB column
262
+ {
263
+ "_version": "1", ← This record uses v1 format
264
+ "id": "abc123",
265
+ "amount": "100" // string in v1
266
+ }
267
+
268
+ version_skew_handling:
269
+ description: "Application code handles multiple data formats"
270
+ pattern: |
271
+ def parse_dilemma(data: dict) -> Dilemma:
272
+ version = data.get("_version", "1") # Default to v1
273
+
274
+ if version == "1":
275
+ # OLD FORMAT: amount is string
276
+ return Dilemma(
277
+ id=data["id"],
278
+ amount=int(data["amount"]) # Convert string → int
279
+ )
280
+ else: # version 2+
281
+ # NEW FORMAT: amount is int
282
+ return Dilemma(
283
+ id=data["id"],
284
+ amount=data["amount"] # Already int
285
+ )
286
+
287
+ semantic_versioning_rules: |
288
+ | Change | Version | Example | Migration Needed? |
289
+ |-----------------------|---------|----------------------|----------------------------|
290
+ | Remove required field | v2.0.0 | amount deleted | ❌ No (JSONB flexible) |
291
+ | Change field type | v2.0.0 | amount: string → int | ❌ No (app handles both) |
292
+ | Add optional field | v1.1.0 | description added | ❌ No (old records lack it) |
293
+ | Fix docs | v1.0.1 | Better descriptions | ❌ No |
294
+
295
+ lifecycle_signals: |
296
+ - v0.x.x = Draft (planner/tester iterating on structure)
297
+ - v1.x.x+ = Stable (published, used by runtime code)
298
+ - Major bumps = Breaking changes (old code can't read new format without _version check)
299
+
300
+ # Supabase CLI Integration
301
+ cli_integration:
302
+ description: "Supabase CLI for structural changes only, NOT contract evolution"
303
+ cli_version: "v2.54.11"
304
+
305
+ commands:
306
+ db_diff:
307
+ command: "supabase db diff -f <migration_name>"
308
+ purpose: "Generate migration from local schema changes"
309
+ use_case: "Adding indexes or rare table structure changes"
310
+ example: |
311
+ # After adding an index manually in local DB
312
+ supabase db diff -f add_dilemma_match_index
313
+
314
+ db_push:
315
+ command: "supabase db push"
316
+ purpose: "Apply migrations to remote database"
317
+ use_case: "Deploy new tables or index changes"
318
+ example: |
319
+ # Apply all pending migrations
320
+ supabase db push
321
+
322
+ db_pull:
323
+ command: "supabase db pull"
324
+ purpose: "Sync remote schema to local"
325
+ use_case: "Pull schema changes from production"
326
+ example: |
327
+ # Fetch remote schema
328
+ supabase db pull
329
+
330
+ gen_types_dart:
331
+ command: "supabase gen types dart --linked > lib/types/database.dart"
332
+ purpose: "Generate Dart types from database schema"
333
+ use_case: "Type safety for Dart client code"
334
+ example: |
335
+ # Generate types after schema changes
336
+ supabase gen types dart --linked > lib/types/database.dart
337
+
338
+ workflow:
339
+ description: "When to use migration.py vs Supabase CLI"
340
+
341
+ create_table:
342
+ trigger: "New contract introduced"
343
+ tool: "migration.py"
344
+ process: |
345
+ 1. Tester generates contract from wagon interface
346
+ 2. migration.py detects new contract
347
+ 3. Generates CREATE TABLE migration with standard JSONB structure
348
+ 4. Human reviews (no TODO markers for JSONB approach)
349
+ 5. Apply: supabase db push
350
+
351
+ add_index:
352
+ trigger: "Discover slow query pattern in production"
353
+ tool: "Supabase CLI"
354
+ process: |
355
+ 1. Identify query performance issue
356
+ 2. Add index manually in local DB for testing
357
+ 3. Generate migration: supabase db diff -f add_index_name
358
+ 4. Review generated migration
359
+ 5. Apply: supabase db push
360
+
361
+ contract_evolution:
362
+ trigger: "Contract schema changes (field add/remove/type change)"
363
+ tool: "❌ NO MIGRATION NEEDED"
364
+ process: |
365
+ 1. Update contract schema version (e.g., 1.0.0 → 2.0.0)
366
+ 2. Add _version field to contract properties if not present
367
+ 3. Update application code to handle version skew
368
+ 4. Deploy code changes
369
+ 5. No database migration required
370
+
371
+ structural_vs_schema:
372
+ structural_migrations:
373
+ description: "Changes to database structure"
374
+ examples: ["CREATE TABLE", "DROP TABLE", "CREATE INDEX", "ALTER TABLE ADD COLUMN (rare)"]
375
+ tool: "migration.py (CREATE) or Supabase CLI (INDEX/ALTER)"
376
+
377
+ schema_evolution:
378
+ description: "Changes to contract schema"
379
+ examples: ["Add field", "Remove field", "Change type", "Rename field"]
380
+ tool: "❌ No migration - handled in application code via _version"
381
+
382
+ # ============================================================================
383
+ # TABLE CATEGORIES (Added in v1.1)
384
+ # ============================================================================
385
+ table_categories:
386
+ description: "Distinguish contract tables from infrastructure tables"
387
+
388
+ contract_tables:
389
+ definition: "Tables storing wagon contracts (data interchange between wagons)"
390
+ pattern: "JSONB blob storage (see jsonb_strategy section)"
391
+ examples: ["commons_ux_skin", "match_dilemma_current", "match_dilemma_paired"]
392
+ naming: "{theme}_{domain}_{aspect} (from contract path)"
393
+ rationale: |
394
+ - Wagons consume complete contracts as documents
395
+ - Schema evolution via _version field in JSONB
396
+ - No migrations needed for contract changes
397
+
398
+ infrastructure_tables:
399
+ definition: "Tables for event sourcing, caching, queuing (non-contract data)"
400
+ pattern: "Choose pattern based on access patterns and constraints"
401
+ examples: ["domain_impact_events", "preload_card_cache", "background_jobs"]
402
+ naming: "{feature}_{purpose} (descriptive, not contract-derived)"
403
+ rationale: |
404
+ - Optimize for query performance, concurrency, or consistency
405
+ - Pattern choice driven by infrastructure needs, not contract versioning
406
+
407
+ # ============================================================================
408
+ # INFRASTRUCTURE PATTERNS (Added in v1.1)
409
+ # ============================================================================
410
+ infrastructure_patterns:
411
+ event_logs:
412
+ use_when: "Implementing event sourcing pattern (append-only immutable logs)"
413
+ pattern: "Normalized columns for event schema + JSONB for metadata"
414
+ rationale: |
415
+ Event logs have different constraints than contract tables:
416
+ - Events are immutable (no updates → no schema migration risk)
417
+ - Query performance critical (event replay by aggregate_id, timestamp)
418
+ - Type safety critical (corrupt events break state reconstruction)
419
+ - Normalized columns outperform JSONB path queries by 5-8x
420
+
421
+ schema_template: |
422
+ CREATE TABLE {wagon}_events (
423
+ id BIGSERIAL PRIMARY KEY,
424
+ aggregate_id BIGINT NOT NULL,
425
+ event_type VARCHAR(50) NOT NULL,
426
+ event_data JSONB NOT NULL,
427
+ timestamp TIMESTAMPTZ NOT NULL,
428
+ created_at TIMESTAMPTZ DEFAULT NOW()
429
+ -- NOTE: No updated_at - events are immutable
430
+ );
431
+ CREATE INDEX idx_{wagon}_events_aggregate ON {wagon}_events(aggregate_id, timestamp DESC);
432
+
433
+ real_example: |
434
+ CREATE TABLE domain_impact_events (
435
+ id BIGSERIAL PRIMARY KEY,
436
+ match_id BIGINT NOT NULL,
437
+ cell_id VARCHAR(2) NOT NULL CHECK (cell_id ~ '^[adfes][COPFI]$'),
438
+ delta NUMERIC(10, 2) NOT NULL CHECK (delta >= 0),
439
+ timestamp TIMESTAMPTZ NOT NULL,
440
+ event_metadata JSONB DEFAULT '{}'::jsonb,
441
+ created_at TIMESTAMPTZ DEFAULT NOW()
442
+ );
443
+ CREATE INDEX idx_events_match ON domain_impact_events(match_id, timestamp);
444
+
445
+ caches:
446
+ use_when: "Temporary or preloaded data for query optimization"
447
+ pattern: "Hybrid (normalized lookup keys + JSONB payloads)"
448
+ rationale: "Lookups by FKs (normalized) + flexible cache payload (JSONB)"
449
+
450
+ schema_template: |
451
+ CREATE TABLE {feature}_cache (
452
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
453
+ lookup_key UUID NOT NULL,
454
+ cached_data JSONB NOT NULL,
455
+ expires_at TIMESTAMPTZ,
456
+ created_at TIMESTAMPTZ DEFAULT NOW(),
457
+ updated_at TIMESTAMPTZ DEFAULT NOW()
458
+ );
459
+ CREATE INDEX idx_{feature}_cache_lookup ON {feature}_cache (lookup_key);
460
+
461
+ queues:
462
+ use_when: "Background job queues, task scheduling"
463
+ pattern: "Normalized columns for queue operations + JSONB for task data"
464
+
465
+ schema_template: |
466
+ CREATE TABLE background_jobs (
467
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
468
+ job_type VARCHAR(50) NOT NULL,
469
+ status VARCHAR(20) NOT NULL CHECK (status IN ('pending', 'running', 'completed', 'failed')),
470
+ priority INT DEFAULT 0,
471
+ scheduled_at TIMESTAMPTZ NOT NULL,
472
+ job_data JSONB NOT NULL,
473
+ created_at TIMESTAMPTZ DEFAULT NOW(),
474
+ updated_at TIMESTAMPTZ DEFAULT NOW()
475
+ );
476
+ CREATE INDEX idx_jobs_queue ON background_jobs (status, priority DESC, scheduled_at)
477
+ WHERE status IN ('pending', 'running');
478
+
479
+ # ============================================================================
480
+ # PATTERN DECISION TREE (Added in v1.1)
481
+ # ============================================================================
482
+ pattern_decision_tree:
483
+ step_1:
484
+ question: "Is this a wagon contract table?"
485
+ yes: "Use JSONB blob pattern → See jsonb_strategy"
486
+ no: "Proceed to step 2"
487
+
488
+ step_2:
489
+ question: "What is the table's purpose?"
490
+ event_log: "Use normalized columns → See infrastructure_patterns.event_logs"
491
+ cache: "Use hybrid pattern → See infrastructure_patterns.caches"
492
+ queue: "Use normalized + JSONB → See infrastructure_patterns.queues"
493
+ other: "Analyze access patterns (high read = normalized, high write = JSONB)"
494
+
495
+ # ============================================================================
496
+ # CHANGELOG
497
+ # ============================================================================
498
+ changelog_v1_1:
499
+ date: "2025-11-08"
500
+ summary: "Add infrastructure patterns for event logs, caches, queues"
501
+ rationale: |
502
+ v1.0 assumed all tables are contract tables. This created confusion for
503
+ event sourcing infrastructure where normalized columns outperform JSONB
504
+ by 5-8x for event replay queries.
505
+
506
+ new_sections:
507
+ - "table_categories: Distinguish contract vs infrastructure"
508
+ - "infrastructure_patterns: Event logs, caches, queues"
509
+ - "pattern_decision_tree: Guide for choosing pattern"