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,1009 @@
1
+ version: "2.0"
2
+ name: "Contract Convention"
3
+ description: "Rules for contract schema structure and metadata. For artifact naming rules, see artifact-naming.convention.yaml"
4
+
5
+ # Naming Authority
6
+ naming_authority:
7
+ convention: "atdd/planner/conventions/artifact-naming.convention.yaml"
8
+ note: |
9
+ For artifact naming rules ($id format, URN pattern, theme taxonomy, separator semantics,
10
+ physical file mapping), refer to artifact-naming.convention.yaml. This convention focuses
11
+ exclusively on contract schema structure and metadata requirements.
12
+
13
+ # Agent Responsibilities
14
+ agent_responsibilities:
15
+ planner:
16
+ role: "Creates wagon/feature manifests in plan/ with produce/consume interfaces"
17
+ output: "Wagon YAML files with artifact declarations"
18
+ location: "plan/{wagon}/_<wagon>.yaml"
19
+
20
+ tester:
21
+ role: "Generates contract schemas from planner interfaces"
22
+ input: "Wagon produce/consume artifacts"
23
+ output: "Contract JSON schema files"
24
+ location: "contracts/{theme}/{domain}/{aspect}.schema.json"
25
+ note: "Full 3-level structure: theme/domain/aspect"
26
+
27
+ principle: "Planner defines WHAT (interfaces), Tester implements HOW (contracts)"
28
+
29
+ # Schema Structure (Root Truth)
30
+ schema_structure:
31
+ description: "Contract schemas follow this structure. Schema is the source of truth."
32
+
33
+ required_fields:
34
+ core:
35
+ - "$schema" # JSON Schema draft-07
36
+ - "$id" # {theme}:{path}:{resource} (hierarchy with colons, NO "contract:" prefix, NO version)
37
+ - "title" # PascalCase name
38
+ - "description" # Purpose description
39
+ - "version" # Semantic version (1.0.0) - separate field, NOT in $id
40
+ - "type" # Always "object"
41
+ - "x-artifact-metadata"
42
+
43
+ metadata_required:
44
+ - "domain" # From artifact name (before colon)
45
+ - "resource" # From artifact name (after colon)
46
+ - "version" # Semantic version
47
+ - "hash" # SHA-256 content hash
48
+ - "producer" # wagon:{name} from wagon produce[]
49
+ - "consumers" # Array of wagon:{name} from consume[] (can be empty array)
50
+ - "dependencies" # Array of contract:{name} this depends on (can be empty array)
51
+ - "api" # HTTP method, path, auth
52
+ - "traceability" # Links to wagon/features (MANDATORY)
53
+
54
+ traceability_required:
55
+ - "wagon_ref" # Path to wagon manifest (MANDATORY)
56
+ - "feature_refs" # Array of feature URNs (MANDATORY, at least 1)
57
+ - "acceptance_refs" # Array of acceptance URNs (optional)
58
+
59
+ id_vs_urn:
60
+ schema_id: "{theme}(:{path})*:{resource}"
61
+ schema_id_examples:
62
+ - "commons:ux:foundations:color"
63
+ - "match:dilemma:current"
64
+ - "mechanic:timebank:exhausted"
65
+ urn: "contract:{theme}(:{path})*:{resource}"
66
+ urn_examples:
67
+ - "contract:commons:ux:foundations:color"
68
+ - "contract:match:dilemma:current"
69
+ note: |
70
+ $id in schema: NO "contract:" prefix (e.g., commons:ux:foundations:color)
71
+ URN in wagon manifests: WITH "contract:" prefix (e.g., contract:commons:ux:foundations:color)
72
+
73
+ Hierarchy (colons) for path depth, mirrors filesystem structure.
74
+ Version is separate field, NOT in $id.
75
+
76
+ Examples:
77
+ File: contracts/commons/ux/foundations/color.schema.json
78
+ $id: commons:ux:foundations:color
79
+ URN: contract:commons:ux:foundations:color
80
+
81
+ properties:
82
+ version:
83
+ type: "string"
84
+ pattern: "^\\d+\\.\\d+\\.\\d+$"
85
+ description: "Semantic version"
86
+
87
+ additionalProperties: false
88
+
89
+ id_format:
90
+ pattern: "{theme}(:{path})*:{resource}"
91
+ description: "Hierarchical identifier with colons for path segments, NO 'contract:' prefix, mirrors filesystem structure"
92
+ examples:
93
+ - "commons:ux:foundations:color"
94
+ - "mechanic:timebank:exhausted"
95
+ - "match:dilemma:current"
96
+ - "player:session:active"
97
+
98
+ template:
99
+ location: "atdd/tester/schemas/contract.tmpl.json"
100
+ purpose: "Template with placeholders for generating new contracts"
101
+
102
+ meta_schema:
103
+ location: "atdd/tester/schemas/contract.schema.json"
104
+ purpose: "Meta-schema that validates common structure of all contracts"
105
+
106
+ # Composite Contracts (Frontend Extensions)
107
+ composite_contracts:
108
+ description: |
109
+ Some contracts define core domain truth while frontends extend them with UI-only
110
+ fields. Contracts must remain UI-agnostic; extensions live in frontend code.
111
+
112
+ rules:
113
+ core_only:
114
+ requirement: "Contract schemas must contain only core domain fields (no UI props)"
115
+ examples_forbidden: ["icon", "color", "tokenKey", "i18nKey", "ariaKey"]
116
+ rationale: "Keep contracts stable and backend-compatible"
117
+
118
+ frontend_extension:
119
+ requirement: "Frontend may extend contract types with UI-specific fields"
120
+ location: "web/src/commons/domain/"
121
+ note: "Extensions must not backflow into contract schema"
122
+
123
+ traceability:
124
+ requirement: "Frontend extensions must reference the contract $id via @contract"
125
+ format: "@contract {schema_id}"
126
+ example: "@contract commons:domain:catalog"
127
+ applies_to: "TypeScript files in web/src/commons/domain/"
128
+
129
+ # Contract Versioning and Lifecycle
130
+ contract_versioning:
131
+ description: "Semantic versioning strategy for contract maturity and backward compatibility tracking"
132
+
133
+ semantic_versioning:
134
+ format: "MAJOR.MINOR.PATCH (e.g., 0.1.0, 1.2.3, 2.0.0)"
135
+ rules:
136
+ major:
137
+ when: "Breaking changes that require code updates"
138
+ examples:
139
+ - "Remove required field"
140
+ - "Change field type (string → number)"
141
+ - "Change field semantics/meaning"
142
+ - "Rename field"
143
+ - "Change $id structure"
144
+ version_bump: "v1.5.2 → v2.0.0"
145
+ backward_compatible: false
146
+ app_impact: "MUST handle both old and new formats"
147
+
148
+ minor:
149
+ when: "Backward-compatible additions"
150
+ examples:
151
+ - "Add optional field"
152
+ - "Add new enum value"
153
+ - "Expand validation (make less strict)"
154
+ - "Add new operation to API"
155
+ version_bump: "v1.2.3 → v1.3.0"
156
+ backward_compatible: true
157
+ app_impact: "Old apps ignore new fields, new apps get bonus data"
158
+
159
+ patch:
160
+ when: "Non-functional changes (no schema impact)"
161
+ examples:
162
+ - "Fix description/documentation"
163
+ - "Fix examples"
164
+ - "Update metadata (traceability, testing refs)"
165
+ - "Improve error messages"
166
+ version_bump: "v1.2.3 → v1.2.4"
167
+ backward_compatible: true
168
+ app_impact: "None - documentation only"
169
+
170
+ lifecycle_stages:
171
+ draft:
172
+ version_range: "0.x.x"
173
+ governance_status: "draft"
174
+ description: "Contract under active development, structure may change"
175
+ created_by: "planner (scaffolded) or tester (initial schema)"
176
+ iteration_rule: "Field additions/changes increment MINOR (0.1.0 → 0.2.0)"
177
+ stability: "Unstable - do not use in production code"
178
+ graduation: "Promote to v1.0.0 when schema is stable and tested"
179
+
180
+ active:
181
+ version_range: "1.x.x+"
182
+ governance_status: "active"
183
+ description: "Stable contract in production use"
184
+ created_by: "tester (promotes from draft)"
185
+ compatibility_guarantee: "Semantic versioning rules enforced"
186
+ breaking_changes: "Require major version bump (v1.x → v2.0)"
187
+ stability: "Stable - safe for production use"
188
+
189
+ deprecated:
190
+ version_range: "Any stable version"
191
+ governance_status: "deprecated"
192
+ description: "Contract sunset warning - will be retired"
193
+ migration_path: "Must document replacement contract"
194
+ timeline: "Provide deprecation timeline (e.g., 6 months)"
195
+ stability: "Stable but discouraged - migrate to replacement"
196
+
197
+ retired:
198
+ version_range: "Any stable version"
199
+ governance_status: "retired"
200
+ description: "Contract no longer supported"
201
+ breaking_change: "Yes - consumers must migrate"
202
+ stability: "Unsupported - do not use"
203
+
204
+ version_in_data:
205
+ description: "Runtime data should include version field for backward compatibility"
206
+ field_name: "_version"
207
+ format: "String with major version (e.g., '1', '2') or full semver (e.g., '1.0.0')"
208
+ purpose: "Allow application code to handle multiple contract versions in JSONB storage"
209
+
210
+ example:
211
+ v1_data:
212
+ _version: "1"
213
+ id: "abc123"
214
+ amount: "100" # string in v1
215
+
216
+ v2_data:
217
+ _version: "2"
218
+ id: "abc123"
219
+ amount: 100 # number in v2
220
+ currency: "USD" # new field in v2
221
+
222
+ application_handling:
223
+ description: "App reads _version field to parse data correctly"
224
+ code_example: |
225
+ def parse_transaction(data: dict) -> Transaction:
226
+ version = data.get("_version", "1") # default to v1 for old records
227
+
228
+ if version == "1":
229
+ return Transaction(
230
+ id=data["id"],
231
+ amount=int(data["amount"]) # convert string to int
232
+ )
233
+ else: # version 2+
234
+ return Transaction(
235
+ id=data["id"],
236
+ amount=data["amount"], # already int
237
+ currency=data.get("currency", "USD") # new field
238
+ )
239
+
240
+ database_migrations:
241
+ description: "Contract version changes vs database schema migrations"
242
+ principle: "JSONB storage decouples contract evolution from database migrations"
243
+
244
+ no_migration_needed:
245
+ - scenario: "Add optional field to contract"
246
+ contract_version: "v1.2.0"
247
+ reason: "Old records lack field, app provides default"
248
+
249
+ - scenario: "Change field type (string → int)"
250
+ contract_version: "v2.0.0"
251
+ reason: "JSONB stores both, app handles per _version"
252
+
253
+ - scenario: "Remove field"
254
+ contract_version: "v2.0.0"
255
+ reason: "Old records still have it in JSONB (ignored)"
256
+
257
+ migration_required:
258
+ - scenario: "New contract introduced"
259
+ contract_version: "v0.1.0"
260
+ migration: "CREATE TABLE if persistent entity"
261
+
262
+ - scenario: "Add query index on JSONB field"
263
+ contract_version: "Any"
264
+ migration: "CREATE INDEX idx_name ON table ((data->>'field'))"
265
+
266
+ - scenario: "Extract frequently-queried field to column"
267
+ contract_version: "Any"
268
+ migration: "ALTER TABLE ADD COLUMN status TEXT GENERATED ALWAYS AS (data->>'status') STORED"
269
+
270
+ version_changelog:
271
+ description: "Maintain CHANGELOG.md for each major contract"
272
+ location: "contracts/{theme}/{domain}/{aspect}/CHANGELOG.md"
273
+ format: "Keep-a-Changelog style"
274
+ example: |
275
+ # Changelog - match:dilemma:current
276
+
277
+ ## [2.0.0] - 2025-11-15
278
+ ### Changed
279
+ - BREAKING: `timeout_ms` changed from string to integer
280
+
281
+ ## [1.1.0] - 2025-10-20
282
+ ### Added
283
+ - Added optional `theme` field to presentation object
284
+
285
+ ## [1.0.0] - 2025-10-01
286
+ ### Changed
287
+ - Promoted from draft to stable
288
+
289
+ ## [0.2.0] - 2025-09-15
290
+ ### Added
291
+ - Added `selection_metadata` object
292
+
293
+ enforcement:
294
+ validation: "Platform tests enforce version format and governance.status presence"
295
+ test_location: "tests/platform_validation/test_contract_versioning.py"
296
+ rules:
297
+ - "version field MUST be present and match semver pattern"
298
+ - "governance.status MUST be present"
299
+ - "0.x.x contracts MUST have status='draft'"
300
+ - "1.x.x+ contracts MUST have status='active', 'deprecated', or 'retired'"
301
+
302
+ # Persistence Traceability
303
+ persistence_traceability:
304
+ description: "Bidirectional traceability between contracts and database tables"
305
+
306
+ purpose: |
307
+ Link contracts to their persistence layer for:
308
+ - Schema evolution tracking (contract changes vs migrations)
309
+ - Impact analysis (what breaks if table changes?)
310
+ - Documentation generation (ER diagrams from contracts)
311
+ - Validation (ensure table exists for persistent contracts)
312
+
313
+ metadata_structure:
314
+ location: "x-artifact-metadata.persistence"
315
+ required_for: "Contracts identified by migration criteria (has 'id' field, persistent entities)"
316
+ optional_for: "Events, DTOs, value objects (transient data)"
317
+
318
+ fields:
319
+ strategy:
320
+ type: "enum: none | jsonb | relational"
321
+ required: true
322
+ values:
323
+ none: "No persistence (events, DTOs, computed values)"
324
+ jsonb: "Document storage in JSONB column (recommended)"
325
+ relational: "Normalized tables with FK relationships (legacy/complex)"
326
+
327
+ table:
328
+ type: "string"
329
+ required: "If strategy != none"
330
+ pattern: "^[a-z][a-z0-9_]*$"
331
+ convention: "{theme}_{domain}_{aspect}"
332
+ examples:
333
+ - "commons_ux_skin"
334
+ - "match_dilemma_current"
335
+ - "match_dilemma_paired"
336
+
337
+ migration:
338
+ type: "string"
339
+ required: "If strategy != none"
340
+ pattern: "supabase/migrations/{timestamp}_{description}.sql"
341
+ purpose: "Link to migration that created this table"
342
+ example: "supabase/migrations/20251030151434_create_entity_tables.sql"
343
+
344
+ indexes:
345
+ type: "array"
346
+ optional: true
347
+ purpose: "Document existing indexes for query optimization"
348
+ structure:
349
+ name: "Index name (e.g., idx_dilemma_current_timestamp)"
350
+ type: "Index type: btree | gin | gist | hash"
351
+ fields: "Indexed fields (JSONB: use -> notation)"
352
+
353
+ examples:
354
+ persistent_entity:
355
+ contract: "match:dilemma:current"
356
+ persistence:
357
+ strategy: "jsonb"
358
+ table: "match_dilemma_current"
359
+ migration: "supabase/migrations/20251030151434_create_entity_tables.sql"
360
+ indexes:
361
+ - name: "idx_match_dilemma_current_data"
362
+ type: "gin"
363
+ fields: ["data"]
364
+ - name: "idx_match_dilemma_current_timestamp"
365
+ type: "btree"
366
+ fields: ["data->'selection_metadata'->>'timestamp'"]
367
+
368
+ ephemeral_event:
369
+ contract: "mechanic:timebank:exhausted"
370
+ persistence:
371
+ strategy: "none"
372
+ note: "Events don't need tables - logged to event streams"
373
+
374
+ value_object:
375
+ contract: "commons:identifiers:uuid"
376
+ persistence:
377
+ strategy: "none"
378
+ note: "Generated on-demand, not stored"
379
+
380
+ naming_convention:
381
+ description: "Table name derived from contract $id"
382
+ pattern: "{theme}_{domain}_{aspect}"
383
+ transformation: "Replace ':' with '_', use snake_case"
384
+
385
+ examples:
386
+ - contract_id: "commons:ux:themes:skin"
387
+ table_name: "commons_ux_skin"
388
+
389
+ - contract_id: "match:dilemma:current"
390
+ table_name: "match_dilemma_current"
391
+
392
+ - contract_id: "player:session:active"
393
+ table_name: "player_session_active"
394
+
395
+ bidirectional_lookup:
396
+ contract_to_table:
397
+ query: "Read contract x-artifact-metadata.persistence.table"
398
+ example: |
399
+ # Python
400
+ with open("contracts/match/dilemma/current.schema.json") as f:
401
+ contract = json.load(f)
402
+ table = contract["x-artifact-metadata"]["persistence"]["table"]
403
+ # → "match_dilemma_current"
404
+
405
+ table_to_contract:
406
+ query: "Read PostgreSQL table COMMENT"
407
+ example: |
408
+ SELECT obj_description('match_dilemma_current'::regclass, 'pg_class');
409
+ -- → "Selected dilemma for player presentation. Contract: match:dilemma:current"
410
+
411
+ registry_approach:
412
+ description: "Generate persistence registry for fast lookup"
413
+ location: ".claude/registry/persistence.yaml"
414
+ structure: |
415
+ tables:
416
+ commons_ux_skin:
417
+ contract: "commons:ux:themes:skin"
418
+ migration: "supabase/migrations/20251030151434_create_entity_tables.sql"
419
+ strategy: "jsonb"
420
+
421
+ match_dilemma_current:
422
+ contract: "match:dilemma:current"
423
+ migration: "supabase/migrations/20251030151434_create_entity_tables.sql"
424
+ strategy: "jsonb"
425
+
426
+ validation:
427
+ rules:
428
+ - rule: "Persistent entities MUST have persistence.strategy != 'none'"
429
+ test: "Check contracts with 'id' field have persistence metadata"
430
+
431
+ - rule: "persistence.table MUST match naming convention"
432
+ test: "Verify table name = contract_id.replace(':', '_')"
433
+
434
+ - rule: "persistence.migration file MUST exist"
435
+ test: "Check migration file exists at specified path"
436
+
437
+ - rule: "Table in database MUST match persistence.table"
438
+ test: "Query Supabase: SELECT table_name FROM information_schema.tables"
439
+
440
+ - rule: "Table COMMENT MUST reference contract $id"
441
+ test: "Query table comment, verify contains contract ID"
442
+
443
+ test_location: "tests/platform_validation/test_persistence_traceability.py"
444
+
445
+ workflow:
446
+ 1_identify_persistent_contracts:
447
+ command: "python atdd/coach/commands/migration.py"
448
+ output: "List of contracts needing persistence"
449
+
450
+ 2_create_migration:
451
+ command: "supabase migration new <name>"
452
+ action: "Write SQL with table name matching contract"
453
+ include: "COMMENT ON TABLE referencing contract $id"
454
+
455
+ 3_update_contract:
456
+ action: "Add persistence metadata to contract"
457
+ fields:
458
+ - "strategy: jsonb"
459
+ - "table: {derived_name}"
460
+ - "migration: supabase/migrations/{timestamp}_{name}.sql"
461
+ - "indexes: [...] (document existing indexes)"
462
+
463
+ 4_apply_migration:
464
+ command: "supabase db push"
465
+ verify: "Table exists in database"
466
+
467
+ 5_validate_traceability:
468
+ command: "pytest tests/platform_validation/test_persistence_traceability.py"
469
+ checks:
470
+ - "Contract persistence.table matches database table"
471
+ - "Migration file exists"
472
+ - "Table comment references contract"
473
+
474
+ # Artifact Metadata Structure
475
+ artifact_metadata:
476
+ description: "x-artifact-metadata captures wagon linkage and governance"
477
+
478
+ required_fields:
479
+ identity:
480
+ - domain # From artifact name (before colon)
481
+ - resource # From artifact name (after colon)
482
+ - version # Semantic version
483
+ - hash # SHA-256 content hash
484
+
485
+ lifecycle:
486
+ - producer # wagon:{name} from wagon produce[]
487
+ - consumers # Array of wagon:{name} from consume[] references (MANDATORY)
488
+ - dependencies # Array of contract:{name} this depends on (MANDATORY - can be empty array)
489
+
490
+ api:
491
+ - method # GET|POST|PUT|DELETE (inferred)
492
+ - path # REST endpoint pattern
493
+
494
+ traceability:
495
+ - wagon_ref # Path to wagon manifest (MANDATORY)
496
+ - feature_refs # Array of feature URNs (MANDATORY - at least 1)
497
+ - acceptance_refs # Array of acceptance URNs (optional)
498
+
499
+ optional_fields:
500
+ - telemetry_refs # Links to telemetry signals
501
+ - governance # Status, stability
502
+ - persistence # Database storage configuration (REQUIRED for persistent entities)
503
+ - testing # Optional test metadata for documentation
504
+ - extensions # Domain-specific metadata
505
+
506
+ rationale: |
507
+ All contracts MUST have complete traceability to:
508
+ - Enable bidirectional navigation (code → plan, plan → code)
509
+ - Support impact analysis for changes
510
+ - Enforce test coverage requirements
511
+ - Maintain governance and audit trails
512
+
513
+ Empty arrays are acceptable for consumers/dependencies when none exist,
514
+ but the fields must be present to make the absence explicit.
515
+
516
+ # Directory Structure
517
+ directory_structure:
518
+ authority: "artifact-naming.convention.yaml (contract_file_mapping section)"
519
+ note: "For physical file path mapping rules, see artifact-naming.convention.yaml"
520
+
521
+ validation:
522
+ meta_validation:
523
+ structure_location: "atdd/tester/validators/test_contracts_structure.py"
524
+ content_location: "atdd/tester/validators/test_contract_schema_compliance.py"
525
+ scope: "Platform-level structural and content validation"
526
+ type: "infrastructure"
527
+ urn_required: false
528
+ checks:
529
+ - "Directory structure (domain/resource hierarchy)"
530
+ - "File naming patterns (*.schema.json)"
531
+ - "JSON Schema Draft-07 compliance"
532
+ - "Required metadata ($schema, $id, version)"
533
+ - "Semantic versioning (MAJOR.MINOR.PATCH)"
534
+ - "Reference integrity (dependencies and $ref)"
535
+ - "Acceptance traceability (acceptance_refs exist)"
536
+ - "Duplicate detection (unique $id)"
537
+
538
+ examples:
539
+ flat:
540
+ - "contracts/commons/ux/foundations/color.schema.json"
541
+
542
+ nested:
543
+ - "contracts/commons/ux/primitives/icons/icon.schema.json"
544
+
545
+ # Contract Generation Workflow
546
+ generation_workflow:
547
+ description: "How tester generates contracts from planner interfaces"
548
+
549
+ inputs:
550
+ - source: "plan/{wagon}/_<wagon>.yaml"
551
+ extract: "produce[] array - artifacts this wagon creates"
552
+
553
+ - source: "All wagon manifests in plan/"
554
+ extract: "consume[] arrays - find consumers of each artifact"
555
+
556
+ - source: "Wagon features[] array"
557
+ extract: "Feature references for traceability"
558
+
559
+ - source: "interface.convention.yaml"
560
+ extract: "Naming patterns and API mapping rules"
561
+
562
+ steps:
563
+ 1_scan_wagons: "Scan all wagon manifests for produce[] artifacts"
564
+ 2_classify: "Parse artifact name → domain, resource, category"
565
+ 3_find_consumers: "Scan all consume[] for references to this artifact"
566
+ 4_extract_deps: "Extract dependencies from producing wagon's consume[]"
567
+ 5_infer_api: "Infer HTTP method from resource name per interface.convention"
568
+ 6_populate_metadata: "Build x-artifact-metadata from collected data"
569
+ 7_generate_schema: "Create contract schema from template"
570
+
571
+ metadata_population:
572
+ theme: "First part of artifact name (before first colon)"
573
+ domain: "Second part of artifact name (between colons)"
574
+ aspect: "Third part of artifact name (after second colon, before dot)"
575
+ producer: "wagon:{name} from wagon declaring in produce[]"
576
+ consumers: "wagon:{name} for each wagon consuming this artifact"
577
+ dependencies: "contract:{name} for each item in producing wagon's consume[]"
578
+
579
+ traceability:
580
+ wagon_ref: "plan/{wagon}/_<wagon>.yaml"
581
+ feature_refs: "Extracted from wagon.features[] array"
582
+ acceptance_refs: "Extracted from feature YAML files (optional)"
583
+
584
+ # API Structure (REST Best Practices)
585
+ api_structure:
586
+ description: "Contract API definitions follow REST best practices with flexible operations"
587
+
588
+ principle: |
589
+ REST APIs organize around resources with multiple operations.
590
+ HTTP methods describe operations (GET, POST, PUT, DELETE), not resource names.
591
+ Each contract can define multiple operations for the same resource.
592
+
593
+ operations_array:
594
+ description: "x-artifact-metadata.api.operations array contains all operations for this contract"
595
+ structure:
596
+ method: "HTTP method (GET, POST, PUT, PATCH, DELETE)"
597
+ path: "REST endpoint path (flexible per operation)"
598
+ description: "Operation description"
599
+ requestBody: "Request schema reference (for POST/PUT/PATCH)"
600
+ responses: "Response schemas mapped to HTTP status codes"
601
+ headers: "Required and optional headers"
602
+ security: "Authentication schemes (OAuth2, JWT, API key)"
603
+ parameters: "Query/path parameters (for collections, filtering)"
604
+ idempotent: "Boolean indicating retry-safety"
605
+
606
+ example:
607
+ operations:
608
+ - method: "GET"
609
+ path: "/players/{id}"
610
+ description: "Retrieve player identity"
611
+ responses:
612
+ "200":
613
+ description: "Player found"
614
+ schema: "$ref: #/definitions/PlayerIdentity"
615
+ "404":
616
+ description: "Player not found"
617
+ schema: "$ref: #/definitions/ErrorResponse"
618
+ headers:
619
+ - name: "Content-Type"
620
+ value: "application/json"
621
+ required: true
622
+ - name: "Authorization"
623
+ description: "Bearer token"
624
+ required: true
625
+ security:
626
+ - type: "jwt"
627
+ scheme: "bearer"
628
+ idempotent: true
629
+
630
+ - method: "PUT"
631
+ path: "/players/{id}"
632
+ description: "Update player identity"
633
+ requestBody:
634
+ schema: "$ref: #/definitions/PlayerIdentity"
635
+ required: true
636
+ responses:
637
+ "200":
638
+ description: "Player updated"
639
+ schema: "$ref: #/definitions/PlayerIdentity"
640
+ "400":
641
+ description: "Invalid request"
642
+ schema: "$ref: #/definitions/ErrorResponse"
643
+ "404":
644
+ description: "Player not found"
645
+ schema: "$ref: #/definitions/ErrorResponse"
646
+ idempotent: true
647
+
648
+ response_schemas:
649
+ description: "Each operation defines response schemas per HTTP status code"
650
+
651
+ status_codes:
652
+ success:
653
+ "200": "OK - Resource retrieved/updated"
654
+ "201": "Created - Resource created"
655
+ "204": "No Content - Resource deleted"
656
+
657
+ client_error:
658
+ "400": "Bad Request - Invalid input"
659
+ "401": "Unauthorized - Authentication required"
660
+ "403": "Forbidden - Insufficient permissions"
661
+ "404": "Not Found - Resource doesn't exist"
662
+ "409": "Conflict - Resource state conflict"
663
+
664
+ server_error:
665
+ "500": "Internal Server Error"
666
+ "503": "Service Unavailable"
667
+
668
+ structure:
669
+ description: "Human-readable description"
670
+ schema: "JSON Schema reference or inline schema"
671
+ headers: "Response headers"
672
+
673
+ error_response_pattern:
674
+ type: "object"
675
+ required: ["error", "message", "timestamp"]
676
+ properties:
677
+ error:
678
+ type: "string"
679
+ description: "Error code"
680
+ message:
681
+ type: "string"
682
+ description: "Human-readable error message"
683
+ details:
684
+ type: "object"
685
+ description: "Additional error context"
686
+ timestamp:
687
+ type: "string"
688
+ format: "date-time"
689
+
690
+ request_schemas:
691
+ description: "POST/PUT/PATCH operations include requestBody schema"
692
+ structure:
693
+ schema: "JSON Schema reference"
694
+ required: "Boolean indicating if body is required"
695
+ contentType: "application/json (default)"
696
+
697
+ example:
698
+ requestBody:
699
+ schema: "$ref: #/definitions/PlayerIdentity"
700
+ required: true
701
+ contentType: "application/json"
702
+
703
+ headers:
704
+ description: "Operations document required and optional headers"
705
+
706
+ standard_headers:
707
+ - name: "Content-Type"
708
+ values: ["application/json", "application/xml"]
709
+ description: "Request/response format"
710
+
711
+ - name: "Accept"
712
+ values: ["application/json", "application/xml"]
713
+ description: "Acceptable response formats"
714
+
715
+ - name: "Authorization"
716
+ format: "Bearer {token}"
717
+ description: "Authentication token"
718
+ required_for: "Protected operations"
719
+
720
+ custom_headers:
721
+ example:
722
+ - name: "X-Request-ID"
723
+ type: "string"
724
+ description: "Unique request identifier for tracing"
725
+
726
+ - name: "X-API-Version"
727
+ type: "string"
728
+ description: "API version override"
729
+
730
+ versioning:
731
+ description: "API versioning enables evolution without breaking changes"
732
+
733
+ strategy: "path-based"
734
+ pattern: "/v{version}/{resource}"
735
+
736
+ examples:
737
+ - version: "v1"
738
+ path: "/v1/players/{id}"
739
+ contract_version: "1.0.0"
740
+
741
+ - version: "v2"
742
+ path: "/v2/players/{id}"
743
+ contract_version: "2.0.0"
744
+ breaking_changes: ["Renamed field 'username' to 'handle'"]
745
+
746
+ version_mapping:
747
+ description: "API version maps to contract schema version"
748
+ rule: "Major API version increment for breaking schema changes"
749
+
750
+ authentication:
751
+ description: "Enhanced auth model supporting OAuth2, JWT, API keys"
752
+
753
+ schemes:
754
+ oauth2:
755
+ type: "oauth2"
756
+ flows:
757
+ authorizationCode:
758
+ authorizationUrl: "/oauth/authorize"
759
+ tokenUrl: "/oauth/token"
760
+ scopes:
761
+ "read:player": "Read player data"
762
+ "write:player": "Modify player data"
763
+
764
+ example:
765
+ security:
766
+ - type: "oauth2"
767
+ scopes: ["read:player", "write:player"]
768
+
769
+ jwt:
770
+ type: "http"
771
+ scheme: "bearer"
772
+ bearerFormat: "JWT"
773
+
774
+ example:
775
+ security:
776
+ - type: "jwt"
777
+ scheme: "bearer"
778
+
779
+ apiKey:
780
+ type: "apiKey"
781
+ in: ["header", "query", "cookie"]
782
+ name: "X-API-Key"
783
+
784
+ example:
785
+ security:
786
+ - type: "apiKey"
787
+ name: "X-API-Key"
788
+ in: "header"
789
+
790
+ none:
791
+ description: "Explicitly mark public endpoints"
792
+ example:
793
+ security: []
794
+
795
+ collection_operations:
796
+ description: "Collections support pagination, filtering, sorting"
797
+
798
+ pagination:
799
+ parameters:
800
+ - name: "page"
801
+ type: "integer"
802
+ description: "Page number (1-indexed)"
803
+ default: 1
804
+
805
+ - name: "limit"
806
+ type: "integer"
807
+ description: "Items per page"
808
+ default: 20
809
+ maximum: 100
810
+
811
+ - name: "offset"
812
+ type: "integer"
813
+ description: "Items to skip (alternative to page)"
814
+
815
+ response_metadata:
816
+ total:
817
+ type: "integer"
818
+ description: "Total items across all pages"
819
+
820
+ page:
821
+ type: "integer"
822
+ description: "Current page number"
823
+
824
+ hasNext:
825
+ type: "boolean"
826
+ description: "More pages available"
827
+
828
+ links:
829
+ type: "object"
830
+ properties:
831
+ next: "URL to next page"
832
+ prev: "URL to previous page"
833
+ first: "URL to first page"
834
+ last: "URL to last page"
835
+
836
+ sorting:
837
+ parameters:
838
+ - name: "sort"
839
+ type: "string"
840
+ description: "Field to sort by"
841
+ example: "createdAt"
842
+
843
+ - name: "order"
844
+ type: "string"
845
+ enum: ["asc", "desc"]
846
+ default: "asc"
847
+
848
+ filtering:
849
+ description: "Field-specific filters via query parameters"
850
+ examples:
851
+ - parameter: "status"
852
+ type: "string"
853
+ description: "Filter by status"
854
+ example: "/players?status=active"
855
+
856
+ - parameter: "createdAfter"
857
+ type: "string"
858
+ format: "date-time"
859
+ description: "Filter by creation date"
860
+ example: "/players?createdAfter=2024-01-01T00:00:00Z"
861
+
862
+ flexible_paths:
863
+ description: "Path patterns are flexible per operation, not rigidly inferred"
864
+
865
+ patterns:
866
+ singular:
867
+ description: "Single resource access"
868
+ examples:
869
+ - "/players/{id}"
870
+ - "/profile"
871
+ - "/session"
872
+
873
+ collection:
874
+ description: "Multiple resource access"
875
+ examples:
876
+ - "/players"
877
+ - "/matches"
878
+ - "/dilemmas"
879
+
880
+ nested:
881
+ description: "Sub-resource access"
882
+ examples:
883
+ - "/matches/{matchId}/dilemmas"
884
+ - "/players/{playerId}/sessions"
885
+ - "/sponsors/{sponsorId}/partnerships"
886
+
887
+ action:
888
+ description: "Action endpoints (not pure CRUD)"
889
+ examples:
890
+ - "/auth/login"
891
+ - "/auth/logout"
892
+ - "/matches/{id}/start"
893
+ - "/matches/{id}/pause"
894
+
895
+ no_rigid_pattern: "Paths defined per operation, NOT inferred from domain name"
896
+
897
+ idempotency:
898
+ description: "Operations document retry-safety behavior"
899
+
900
+ idempotent_methods:
901
+ GET:
902
+ idempotent: true
903
+ description: "Safe to retry, no side effects"
904
+
905
+ PUT:
906
+ idempotent: true
907
+ description: "Multiple identical requests have same effect as single request"
908
+
909
+ DELETE:
910
+ idempotent: true
911
+ description: "Deleting non-existent resource returns same result"
912
+
913
+ non_idempotent_methods:
914
+ POST:
915
+ idempotent: false
916
+ description: "Each request may create new resource"
917
+
918
+ PATCH:
919
+ idempotent: false
920
+ description: "Partial updates may not be idempotent"
921
+
922
+ rest_examples:
923
+ player_identity:
924
+ artifact: "player:identity"
925
+ operations:
926
+ - method: "GET"
927
+ path: "/players/{id}"
928
+ description: "Retrieve player identity"
929
+
930
+ - method: "PUT"
931
+ path: "/players/{id}"
932
+ description: "Update player identity"
933
+
934
+ - method: "DELETE"
935
+ path: "/players/{id}"
936
+ description: "Delete player account"
937
+
938
+ match_dilemma:
939
+ artifact: "match:dilemma"
940
+ operations:
941
+ - method: "GET"
942
+ path: "/matches/{matchId}/dilemmas/{dilemmaId}"
943
+ description: "Get current dilemma in match"
944
+
945
+ - method: "POST"
946
+ path: "/matches/{matchId}/dilemmas"
947
+ description: "Create new dilemma for match"
948
+
949
+ auth_login:
950
+ artifact: "auth:session"
951
+ operations:
952
+ - method: "POST"
953
+ path: "/auth/login"
954
+ description: "Authenticate and create session"
955
+
956
+ - method: "POST"
957
+ path: "/auth/logout"
958
+ description: "End current session"
959
+
960
+ # Validation Rules
961
+ validation:
962
+ schema_requirements:
963
+ id_pattern: "^contract:[a-z_]+:[a-z_]+(\\.[a-z_]+)?$"
964
+ version_pattern: "^\\d+\\.\\d+\\.\\d+$"
965
+ additional_properties: false
966
+ required_fields_enforced: true
967
+
968
+ metadata_requirements:
969
+ producer_format: "^wagon:[a-z\\-]+$"
970
+ consumer_format: "^(wagon|external):[a-z\\-]+$"
971
+ dependency_format: "^contract:[a-z_]+:[a-z_]+(\\.[a-z_]+)?$"
972
+
973
+ bidirectional_linkage:
974
+ wagon_to_contract: "Wagon produce[].urn resolves to contract $id"
975
+ contract_to_wagon: "Contract producer references existing wagon"
976
+
977
+ meta_validation:
978
+ rule: "Contract schema validation is centralized in atdd/tester/audits"
979
+ note: "No co-located tests/ directories are required"
980
+
981
+ # Removed Concepts (Version 2.0)
982
+ removed_concepts:
983
+ - concept: "wagon_contracts vs design_contracts distinction"
984
+ reason: "All contracts come from wagons. UX wagon produces contracts just like any other wagon."
985
+ removed_in: "v2.0"
986
+
987
+ - concept: "I/O type classification (dto/command/event/query)"
988
+ reason: "Implementation detail, not contract interface concern. Contracts are agnostic."
989
+ removed_in: "v2.0"
990
+
991
+ - concept: "Port mapping (Http/Repo/Bus/Knowledge)"
992
+ reason: "Internal routing concern, not exposed in contract schema."
993
+ removed_in: "v2.0"
994
+
995
+ - concept: "SDK generation metadata in contracts"
996
+ reason: "Tooling concern. SDK generation derives from contracts independently."
997
+ removed_in: "v2.0"
998
+
999
+ - concept: "Pack manifest integration"
1000
+ reason: "Packaging concern, separate from contract definition."
1001
+ removed_in: "v2.0"
1002
+
1003
+ # Cross-References
1004
+ references:
1005
+ naming_authority: "atdd/planner/conventions/interface.convention.yaml"
1006
+ schema_template: "atdd/tester/schemas/contract.tmpl.json"
1007
+ schema_validator: "atdd/tester/schemas/contract.schema.json"
1008
+ telemetry_example: "atdd/tester/schemas/telemetry.schema.json"
1009
+ platform_validation: "atdd/tester/validators/test_contracts_structure.py"