atdd 0.7.1__py3-none-any.whl → 0.7.2__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.
@@ -10,7 +10,7 @@ Architecture: 4-Layer Clean Architecture (single file)
10
10
  Registries:
11
11
  - plan/_wagons.yaml from wagon manifests
12
12
  - contracts/_artifacts.yaml from contract schemas
13
- - telemetry/_signals.yaml from telemetry signals
13
+ - telemetry/_telemetry.yaml from telemetry signals
14
14
  - atdd/tester/_tests.yaml from test files
15
15
  - python/_implementations.yaml from Python files
16
16
  - supabase/_functions.yaml from function files
@@ -89,8 +89,8 @@ class RegistryLoader:
89
89
  return yaml.safe_load(f) or {"artifacts": []}
90
90
 
91
91
  def load_telemetry(self) -> Dict[str, Any]:
92
- """Load telemetry registry (telemetry/_signals.yaml)."""
93
- registry_path = self.telemetry_dir / "_signals.yaml"
92
+ """Load telemetry registry (telemetry/_telemetry.yaml)."""
93
+ registry_path = self.telemetry_dir / "_telemetry.yaml"
94
94
  if not registry_path.exists():
95
95
  return {"signals": []}
96
96
 
@@ -776,7 +776,7 @@ class RegistryBuilder:
776
776
 
777
777
  def update_telemetry_registry(self, mode: str = "interactive", preview_only: bool = None) -> Dict[str, Any]:
778
778
  """
779
- Update telemetry/_signals.yaml from telemetry signal files.
779
+ Update telemetry/_telemetry.yaml from telemetry signal files.
780
780
 
781
781
  Args:
782
782
  mode: "interactive" (prompt), "apply" (no prompt), or "check" (verify only)
@@ -791,7 +791,7 @@ class RegistryBuilder:
791
791
  print("\n📊 Analyzing telemetry registry from signal files...")
792
792
 
793
793
  # Load existing registry
794
- registry_path = self.telemetry_dir / "_signals.yaml"
794
+ registry_path = self.telemetry_dir / "_telemetry.yaml"
795
795
  existing_signals = {}
796
796
  if registry_path.exists():
797
797
  with open(registry_path) as f:
@@ -812,7 +812,7 @@ class RegistryBuilder:
812
812
  # Scan for telemetry signal files (JSON or YAML)
813
813
  json_files = list(self.telemetry_dir.glob("**/*.json"))
814
814
  yaml_files = list(self.telemetry_dir.glob("**/*.yaml"))
815
- signal_files = [f for f in (json_files + yaml_files) if "_signals" not in f.name]
815
+ signal_files = [f for f in (json_files + yaml_files) if "_telemetry" not in f.name]
816
816
 
817
817
  stats["total_files"] = len(signal_files)
818
818
 
@@ -1435,8 +1435,8 @@ class TraceabilityReconciler:
1435
1435
 
1436
1436
  for telemetry in telemetry_files:
1437
1437
  # Skip manifest and pack files (not signal files)
1438
- if (telemetry.file_path.endswith('_tracking.yaml') or
1439
- telemetry.file_path.endswith('_signals.yaml') or
1438
+ if (telemetry.file_path.endswith('_taxonomy.yaml') or
1439
+ telemetry.file_path.endswith('_telemetry.yaml') or
1440
1440
  '.pack.' in telemetry.file_path):
1441
1441
  continue
1442
1442
 
@@ -1493,9 +1493,9 @@ class TraceabilityReconciler:
1493
1493
 
1494
1494
  telemetry_id = telemetry.telemetry_id
1495
1495
 
1496
- # Skip manifest files (_tracking.yaml, _signals.yaml)
1497
- if telemetry.file_path.endswith('_tracking.yaml') or \
1498
- telemetry.file_path.endswith('_signals.yaml') or \
1496
+ # Skip manifest files (_taxonomy.yaml, _telemetry.yaml)
1497
+ if telemetry.file_path.endswith('_taxonomy.yaml') or \
1498
+ telemetry.file_path.endswith('_telemetry.yaml') or \
1499
1499
  '.pack.' in telemetry.file_path:
1500
1500
  continue
1501
1501
 
@@ -0,0 +1,296 @@
1
+ version: "1.0"
2
+ name: "Master Naming Convention"
3
+ description: "Consolidated naming patterns for all ATDD archetypes with regex validation"
4
+
5
+ # Purpose
6
+ purpose: |
7
+ Single source of truth for naming patterns across all archetypes.
8
+ Each archetype has: pattern, regex, examples, and validator reference.
9
+ For detailed semantics, see archetype-specific conventions.
10
+
11
+ # Separator Semantics (from artifact-naming.convention.yaml)
12
+ separator_semantics:
13
+ colon: "Hierarchical descent (unlimited depth)"
14
+ dot: "Lateral variation (typically 0-1 levels)"
15
+ hyphen: "Word separator within segments (kebab-case)"
16
+
17
+ # Naming Patterns by Archetype
18
+ patterns:
19
+
20
+ wagon:
21
+ description: "Bounded context performing specific action on specific object"
22
+ semantic_pattern: "verb-object"
23
+ format: "kebab-case"
24
+ regex: "^[a-z][a-z0-9]*-[a-z][a-z0-9]*(-[a-z][a-z0-9]*)*$"
25
+ urn_format: "wagon:{wagon-name}"
26
+ urn_regex: "^wagon:[a-z][a-z0-9-]+$"
27
+ examples:
28
+ valid:
29
+ - "authenticate-identity"
30
+ - "resolve-dilemmas"
31
+ - "commit-state"
32
+ - "burn-timebank"
33
+ - "juggle-domains"
34
+ - "manage-inventory"
35
+ invalid:
36
+ - "authentication" # Missing object (noun only)
37
+ - "dilemma-resolver" # Wrong order (object-verb)
38
+ - "resolving-dilemmas" # Gerund instead of verb
39
+ - "ResolveDilemmas" # PascalCase
40
+ filesystem:
41
+ directory: "plan/{wagon_snake_case}/"
42
+ manifest: "plan/{wagon_snake_case}/_{wagon_snake_case}.yaml"
43
+ note: "Directory uses snake_case: resolve_dilemmas"
44
+ validator:
45
+ file: "src/atdd/planner/validators/test_plan_wagons.py"
46
+ spec: "SPEC-PLATFORM-WAGONS-0008"
47
+ convention_ref: "atdd/planner/conventions/wagon.convention.yaml"
48
+
49
+ feature:
50
+ description: "Specific capability within a wagon"
51
+ semantic_pattern: "verb-object"
52
+ format: "kebab-case"
53
+ regex: "^[a-z][a-z0-9]*-[a-z][a-z0-9]*(-[a-z][a-z0-9]*)*$"
54
+ urn_format: "feature:{wagon}:{feature-name}"
55
+ urn_regex: "^feature:[a-z][a-z0-9-]+:[a-z][a-z0-9-]+$"
56
+ examples:
57
+ valid:
58
+ - "capture-choice"
59
+ - "pair-fragments"
60
+ - "score-domains"
61
+ - "sign-commit"
62
+ - "validate-input"
63
+ invalid:
64
+ - "choice-capture" # Wrong order
65
+ - "capturing" # Missing object
66
+ - "fragment_pairing" # Snake case
67
+ filesystem:
68
+ file: "plan/{wagon}/features/{feature_snake_case}.yaml"
69
+ validator:
70
+ file: "src/atdd/planner/validators/test_plan_wagons.py"
71
+ spec: "SPEC-PLATFORM-WAGONS-0009"
72
+ convention_ref: "atdd/planner/conventions/feature.convention.yaml"
73
+
74
+ contract:
75
+ description: "Data exchange contract between wagons"
76
+ semantic_pattern: "theme:hierarchy:aspect(.variant)?"
77
+ format: "kebab-case segments with colon/dot separators"
78
+ id_regex: "^[a-z][a-z0-9-]*(:[a-z][a-z0-9-]+)+(\\.[a-z][a-z0-9-]+)?$"
79
+ urn_format: "contract:{artifact-name}"
80
+ urn_regex: "^contract:[a-z][a-z0-9-]*(:[a-z][a-z0-9-]+)+(\\.[a-z][a-z0-9-]+)?$"
81
+ examples:
82
+ schema_id:
83
+ - "mechanic:timebank.remaining"
84
+ - "match:dilemma:current"
85
+ - "commons:ux:foundations:color"
86
+ - "sensory:gesture.raw"
87
+ urn:
88
+ - "contract:mechanic:timebank.remaining"
89
+ - "contract:match:dilemma:current"
90
+ - "contract:commons:ux:foundations:color"
91
+ id_vs_urn:
92
+ schema_id: "NO 'contract:' prefix (e.g., mechanic:timebank.remaining)"
93
+ wagon_urn: "WITH 'contract:' prefix (e.g., contract:mechanic:timebank.remaining)"
94
+ filesystem:
95
+ pattern: "contracts/{theme}/{domain}/{aspect}.schema.json"
96
+ example: "contracts/mechanic/timebank/remaining.schema.json"
97
+ validator:
98
+ file: "src/atdd/tester/validators/test_contract_schema_compliance.py"
99
+ spec: "SPEC-TESTER-VAL-0001"
100
+ convention_ref: "atdd/tester/conventions/contract.convention.yaml"
101
+ naming_authority: "atdd/planner/conventions/artifact-naming.convention.yaml"
102
+
103
+ telemetry:
104
+ description: "Observability and analytics tracking signals"
105
+ semantic_pattern: "theme:hierarchy:aspect(.variant)?"
106
+ format: "kebab-case segments with colon/dot separators"
107
+ signal_id_regex: "^[a-z][a-z0-9-]*(:[a-z][a-z0-9-]+)+\\.(event|metric|trace|log)\\.(ui|ux|be|db|nw|st|tm|sc|au|fn|if)(\\.[a-z][a-z0-9-]+)?$"
108
+ urn_format: "telemetry:{theme}(:{path})*:{aspect}(.{variant})?"
109
+ urn_regex: "^telemetry:[a-z][a-z0-9-]*(:[a-z][a-z0-9-]+)*(\\.[a-z][a-z0-9-]+)?$"
110
+ examples:
111
+ signal_id:
112
+ - "mechanic:decision.choice.event.be"
113
+ - "match:dilemma:current.metric.be.selection-duration"
114
+ - "juggle:goal.detected.event.be"
115
+ urn:
116
+ - "telemetry:mechanic:decision.choice"
117
+ - "telemetry:juggle:goal.detected"
118
+ - "telemetry:mechanic:episode.timer"
119
+ id_vs_urn:
120
+ signal_id: "NO 'telemetry:' prefix, includes .type.plane (e.g., mechanic:decision.choice.event.be)"
121
+ wagon_urn: "WITH 'telemetry:' prefix, NO type.plane (e.g., telemetry:mechanic:decision.choice)"
122
+ filesystem:
123
+ pattern: "telemetry/{theme}/{domain}/{aspect}.{type}.{plane}[.{measure}].json"
124
+ example: "telemetry/mechanic/decision/choice.event.be.json"
125
+ validator:
126
+ file: "src/atdd/tester/validators/test_telemetry_structure.py"
127
+ spec: "SPEC-TESTER-CONV-0050"
128
+ convention_ref: "atdd/tester/conventions/telemetry.convention.yaml"
129
+
130
+ train:
131
+ description: "User journey or end-to-end workflow"
132
+ semantic_pattern: "{NNNN}-{slug}"
133
+ format: "4-digit hierarchical prefix + kebab-case slug"
134
+ regex: "^\\d{4}-[a-z][a-z0-9-]+$"
135
+ numbering:
136
+ pattern: "[Theme][Category][Variation]-{slug}"
137
+ theme_digit: "0-9 (commons=0, mechanic=1, scenario=2, match=3, etc.)"
138
+ category_digit: "0=nominal, 1=error, 2=alternate, 3=exception"
139
+ variation_digits: "01-99"
140
+ examples:
141
+ valid:
142
+ - "1001-decision-standard"
143
+ - "3006-episode-match-complete"
144
+ - "0201-sso-authentication"
145
+ - "2301-empty-input-file"
146
+ invalid:
147
+ - "101-decision" # Only 3 digits
148
+ - "1001_decision" # Underscore
149
+ - "1001-Decision" # PascalCase
150
+ filesystem:
151
+ registry: "plan/_trains.yaml"
152
+ spec: "plan/_trains/{train_id}.yaml"
153
+ validator:
154
+ file: "src/atdd/planner/validators/test_train_validation.py"
155
+ spec: "SPEC-TRAIN-VAL-0001"
156
+ convention_ref: "atdd/planner/conventions/train.convention.yaml"
157
+
158
+ acceptance:
159
+ description: "Acceptance criteria URN for test traceability"
160
+ semantic_pattern: "acc:{wagon}:{wmbt}-{harness}-{NNN}[-{slug}]"
161
+ format: "Structured URN with step code, harness, and sequence"
162
+ regex: "^acc:[a-z][a-z0-9_-]+:([DLPCEMYRK][0-9]{3}-(UNIT|HTTP|EVENT|WS|E2E|A11Y|VIS|METRIC|JOB|DB|SEC|LOAD|SCRIPT|WIDGET|GOLDEN|BLOC|INTEGRATION|RLS|EDGE|REALTIME|STORAGE)-[0-9]{3}(?:-[a-z0-9-]+)?|[A-Z][0-9]{3})$"
163
+ components:
164
+ wagon: "Parent wagon (kebab-case)"
165
+ wmbt_id: "Step code [DLPCEMYRK] + 3-digit sequence (e.g., C004)"
166
+ harness: "Test harness type (uppercase)"
167
+ sequence: "Zero-padded 3-digit number (001-999)"
168
+ slug: "Optional kebab-case descriptor"
169
+ step_codes:
170
+ D: "Discovery"
171
+ L: "Load"
172
+ P: "Parse"
173
+ C: "Compute"
174
+ E: "Emit"
175
+ M: "Mutate"
176
+ Y: "Yield"
177
+ R: "Render"
178
+ K: "Keep"
179
+ harness_types:
180
+ - "UNIT"
181
+ - "HTTP"
182
+ - "EVENT"
183
+ - "WS"
184
+ - "E2E"
185
+ - "A11Y"
186
+ - "VIS"
187
+ - "METRIC"
188
+ - "JOB"
189
+ - "DB"
190
+ - "SEC"
191
+ - "LOAD"
192
+ - "SCRIPT"
193
+ - "WIDGET"
194
+ - "GOLDEN"
195
+ - "BLOC"
196
+ - "INTEGRATION"
197
+ - "RLS"
198
+ - "EDGE"
199
+ - "REALTIME"
200
+ - "STORAGE"
201
+ examples:
202
+ valid:
203
+ - "acc:commit-state:M001-INTEGRATION-001"
204
+ - "acc:pace-dilemmas:P011-VISUAL-001"
205
+ - "acc:maintain-ux:C004-E2E-019-user-connection"
206
+ - "acc:resolve-dilemmas:C001-UNIT-001-choice-validation"
207
+ invalid:
208
+ - "acc:commit-state:M01-INTEGRATION-001" # Only 2 digits in WMBT
209
+ - "acc:commit-state:M001-integration-001" # Lowercase harness
210
+ - "acc:commit-state:M001-INTEGRATION-01" # Only 2 digits in sequence
211
+ validator:
212
+ file: "src/atdd/tester/validators/test_contract_schema_compliance.py"
213
+ spec: "SPEC-TESTER-VAL-0020"
214
+ convention_ref: "atdd/planner/conventions/acceptance.convention.yaml"
215
+
216
+ wmbt:
217
+ description: "What Must Be True step identifier"
218
+ semantic_pattern: "wmbt:{wagon}:{step_code}{NNN}"
219
+ format: "Step code letter + 3-digit sequence"
220
+ regex: "^wmbt:[a-z][a-z0-9-]+:[DLPCEMYRK][0-9]{3}$"
221
+ examples:
222
+ valid:
223
+ - "wmbt:resolve-dilemmas:C001"
224
+ - "wmbt:commit-state:M001"
225
+ - "wmbt:pace-dilemmas:P011"
226
+ invalid:
227
+ - "wmbt:resolve-dilemmas:C01" # Only 2 digits
228
+ - "wmbt:resolve-dilemmas:X001" # Invalid step code
229
+ filesystem:
230
+ file: "plan/{wagon}/wmbt/{step_code}{NNN}.yaml"
231
+ validator:
232
+ file: "src/atdd/planner/validators/test_wmbt_consistency.py"
233
+ spec: "SPEC-PLANNER-VAL-0030"
234
+ convention_ref: "atdd/planner/conventions/wmbt.convention.yaml"
235
+
236
+ appendix:
237
+ description: "Supplementary reference data"
238
+ semantic_pattern: "appendix:{type}"
239
+ format: "kebab-case type identifier"
240
+ regex: "^appendix:[a-z][a-z0-9-]+$"
241
+ examples:
242
+ valid:
243
+ - "appendix:theme-catalog"
244
+ - "appendix:error-codes"
245
+ - "appendix:locale-mappings"
246
+ invalid:
247
+ - "appendix:ThemeCatalog" # PascalCase
248
+ - "appendix_theme" # Underscore separator
249
+ note: "Currently not strictly enforced - documentation pattern"
250
+ validator:
251
+ file: "Not yet implemented"
252
+ spec: "Pending"
253
+
254
+ system:
255
+ description: "External system or service reference"
256
+ semantic_pattern: "system:{service-name}"
257
+ format: "kebab-case service identifier"
258
+ regex: "^system:[a-z][a-z0-9-]+$"
259
+ examples:
260
+ valid:
261
+ - "system:external"
262
+ - "system:scenario-library"
263
+ - "system:filesystem"
264
+ - "system:posthog"
265
+ invalid:
266
+ - "system:External" # PascalCase
267
+ - "external-system" # Missing prefix
268
+ note: "Used in wagon consume references for external dependencies"
269
+ validator:
270
+ file: "Not yet implemented"
271
+ spec: "Pending"
272
+
273
+ # Validation Summary
274
+ validation_summary:
275
+ enforced:
276
+ - wagon: "SPEC-PLATFORM-WAGONS-0008"
277
+ - feature: "SPEC-PLATFORM-WAGONS-0009"
278
+ - contract: "SPEC-PLATFORM-WAGONS-0006"
279
+ - telemetry: "SPEC-PLATFORM-WAGONS-0007"
280
+ - train: "SPEC-TRAIN-VAL-0001"
281
+ - acceptance: "SPEC-TESTER-VAL-0020"
282
+ - wmbt: "SPEC-PLANNER-VAL-0030"
283
+ pending:
284
+ - appendix: "Not yet enforced"
285
+ - system: "Not yet enforced"
286
+
287
+ # Cross-References
288
+ references:
289
+ artifact_naming: "atdd/planner/conventions/artifact-naming.convention.yaml"
290
+ wagon: "atdd/planner/conventions/wagon.convention.yaml"
291
+ feature: "atdd/planner/conventions/feature.convention.yaml"
292
+ contract: "atdd/tester/conventions/contract.convention.yaml"
293
+ telemetry: "atdd/tester/conventions/telemetry.convention.yaml"
294
+ train: "atdd/planner/conventions/train.convention.yaml"
295
+ acceptance: "atdd/planner/conventions/acceptance.convention.yaml"
296
+ wmbt: "atdd/planner/conventions/wmbt.convention.yaml"
@@ -354,6 +354,7 @@ archetypes:
354
354
  id: "telemetry"
355
355
  description: "Observability and monitoring artifacts"
356
356
  artifacts:
357
+ - "telemetry/_taxonomy.yaml"
357
358
  - "telemetry/_telemetry.yaml"
358
359
  - "telemetry/{domain}/*.yaml"
359
360
  patterns:
@@ -53,6 +53,7 @@ manifest:
53
53
  - artifacts: "contracts/_artifacts.yaml"
54
54
  - contracts: "contracts/_contracts.yaml"
55
55
  - telemetry: "telemetry/_telemetry.yaml"
56
+ - taxonomy: "telemetry/_taxonomy.yaml"
56
57
 
57
58
  tests:
58
59
  - frontend: "web/tests"
@@ -21,6 +21,10 @@ type: "{type}" # implementation | migration | refactor | analysis | planning |
21
21
  complexity: 3 # 1=Trivial, 2=Low, 3=Medium, 4=High, 5=Very High
22
22
  archetypes:
23
23
  - "{archetype}" # db | be | fe | contracts | wmbt | wagon | train | telemetry | migrations
24
+ # NOTE: If archetypes includes 'train', you MUST create/update BOTH:
25
+ # 1. plan/_trains.yaml (registry entry with train_id, description, path, wagons)
26
+ # 2. plan/_trains/{train_id}.yaml (full spec with participants, sequence, etc.)
27
+ # Validator SPEC-TRAIN-VAL-0003 enforces spec file exists for each registry entry.
24
28
 
25
29
  # Scope definition
26
30
  scope:
@@ -38,7 +42,8 @@ workflow_phases:
38
42
  planner:
39
43
  status: "TODO" # TODO | IN_PROGRESS | DONE | SKIPPED | N/A
40
44
  artifacts:
41
- train: false # plan/_trains.yaml updated
45
+ train: false # plan/_trains.yaml updated (registry entry)
46
+ train_spec: false # plan/_trains/{train_id}.yaml exists (full spec)
42
47
  wagon: false # plan/{wagon}/_{wagon}.yaml exists
43
48
  feature: false # plan/{wagon}/features/{feature}.yaml exists
44
49
  wmbt: false # WMBTs defined in feature YAML
@@ -257,6 +257,23 @@ registry:
257
257
  structure: "theme-category-grouped"
258
258
  description: "Trains grouped by theme, then by category (nominal/error/alternate/exception) in _trains.yaml manifest"
259
259
 
260
+ # Two-file pattern: Registry + Per-Train Spec Files
261
+ two_file_pattern:
262
+ description: "Each train requires two files: a registry entry and a spec file"
263
+ files:
264
+ registry:
265
+ path: "plan/_trains.yaml"
266
+ purpose: "Central manifest listing all trains with summary metadata"
267
+ contains: "train_id, description, path, wagons (summary list)"
268
+ spec:
269
+ path: "plan/_trains/{train_id}.yaml"
270
+ purpose: "Full train specification with complete workflow definition"
271
+ contains: "train_id, title, themes, participants, sequence, dependencies, test, code, expectations"
272
+ validation:
273
+ rule: "Every registry entry MUST have a corresponding spec file"
274
+ validator: "SPEC-TRAIN-VAL-0003 (test_train_files_exist_for_registry_entries)"
275
+ enforcement: "Planner phase gate fails if spec file missing"
276
+
260
277
  format: |
261
278
  trains:
262
279
  0-commons:
@@ -95,6 +95,72 @@ def test_wagon_slugs_match_directory_names(wagon_manifests):
95
95
  f"Wagon slug '{wagon_slug}' doesn't match expected slug '{expected_slug}' (from directory '{directory_name}') for {path}"
96
96
 
97
97
 
98
+ @pytest.mark.platform
99
+ def test_wagon_names_follow_verb_object_pattern(wagon_manifests):
100
+ """
101
+ SPEC-PLATFORM-WAGONS-0008: Wagon names follow verb-object semantic pattern
102
+
103
+ Given: All wagon manifests
104
+ When: Checking wagon name format
105
+ Then: Wagon names follow verb-object pattern (e.g., resolve-dilemmas, commit-state)
106
+ - Format: verb-object (kebab-case, at least 2 hyphen-separated words)
107
+ - First segment should be a verb (action)
108
+ - Subsequent segments describe the object/domain
109
+ Per naming.convention.yaml wagon section
110
+ """
111
+ import re
112
+
113
+ # Pattern: verb-object with optional additional words (e.g., burn-timebank, juggle-domains)
114
+ # Requires at least 2 segments separated by hyphens
115
+ verb_object_pattern = re.compile(r"^[a-z][a-z0-9]*-[a-z][a-z0-9]*(-[a-z][a-z0-9]*)*$")
116
+
117
+ for path, manifest in wagon_manifests:
118
+ wagon_name = manifest.get("wagon", "")
119
+ if wagon_name:
120
+ assert verb_object_pattern.match(wagon_name), \
121
+ f"Wagon {path}: name '{wagon_name}' doesn't follow verb-object pattern (e.g., resolve-dilemmas)"
122
+
123
+
124
+ @pytest.mark.platform
125
+ def test_feature_names_follow_verb_object_pattern(wagon_manifests):
126
+ """
127
+ SPEC-PLATFORM-WAGONS-0009: Feature names follow verb-object semantic pattern
128
+
129
+ Given: All wagon manifests with features[] entries
130
+ When: Checking feature name format from URNs
131
+ Then: Feature names follow verb-object pattern (e.g., capture-choice, pair-fragments)
132
+ - URN format: feature:{wagon}:{feature-name}
133
+ - Feature name requires at least 2 hyphen-separated words
134
+ Per naming.convention.yaml feature section
135
+ """
136
+ import re
137
+
138
+ # Pattern: verb-object with optional additional words
139
+ verb_object_pattern = re.compile(r"^[a-z][a-z0-9]*-[a-z][a-z0-9]*(-[a-z][a-z0-9]*)*$")
140
+
141
+ for path, manifest in wagon_manifests:
142
+ features_list = manifest.get("features", [])
143
+ wagon_name = manifest.get("wagon", "")
144
+
145
+ for feature in features_list:
146
+ feature_name = None
147
+
148
+ # Extract feature name from URN
149
+ if isinstance(feature, dict) and "urn" in feature:
150
+ urn = feature["urn"]
151
+ parts = urn.split(":")
152
+ if len(parts) >= 3:
153
+ feature_name = parts[2]
154
+ elif isinstance(feature, str) and feature.startswith("feature:"):
155
+ parts = feature.split(":")
156
+ if len(parts) >= 3:
157
+ feature_name = parts[2]
158
+
159
+ if feature_name:
160
+ assert verb_object_pattern.match(feature_name), \
161
+ f"Wagon {wagon_name}: feature '{feature_name}' doesn't follow verb-object pattern (e.g., capture-choice)"
162
+
163
+
98
164
  @pytest.mark.platform
99
165
  def test_produce_artifact_names_follow_convention(wagon_manifests):
100
166
  """
@@ -153,9 +219,10 @@ def test_telemetry_urns_match_pattern(wagon_manifests):
153
219
 
154
220
  Given: Wagon produce items with non-null telemetry URNs
155
221
  When: Validating URN format
156
- Then: Telemetry URNs match pattern telemetry:{path}:{aspect}
157
- Supports multi-level paths (e.g., telemetry:commons:ux:foundations)
158
- Uses colons (not dots) for hierarchy
222
+ Then: Telemetry URNs match pattern telemetry:{path}:{aspect}(.{variant})?
223
+ - Colons (:) for hierarchical descent (e.g., telemetry:commons:ux:foundations)
224
+ - Dots (.) for lateral variants (e.g., telemetry:mechanic:decision.choice)
225
+ Per telemetry.convention.yaml id_vs_urn section
159
226
  """
160
227
  import re
161
228
 
@@ -318,7 +318,7 @@ tracking_structure:
318
318
  version: "1.1.0"
319
319
 
320
320
  manifest:
321
- location: "telemetry/_tracking.yaml"
321
+ location: "telemetry/_taxonomy.yaml"
322
322
  format: "YAML"
323
323
  purpose: "Central registry of all telemetry signals per artifact"
324
324
 
@@ -401,18 +401,23 @@ tracking_structure:
401
401
  signal_id_examples:
402
402
  - "commons:ux:foundations:color.metric.be.count"
403
403
  - "match:dilemma:current.metric.be.selection_duration"
404
- - "commons:ux:foundations:foundations.metric.be.error_rate"
405
- urn: "telemetry:{theme}(:{path})*:{aspect}"
404
+ - "mechanic:decision.choice.event.be"
405
+ urn: "telemetry:{theme}(:{path})*:{aspect}(.{variant})?"
406
406
  urn_examples:
407
- - "telemetry:commons:ux:foundations"
408
- - "telemetry:match:dilemma"
407
+ - "telemetry:mechanic:decision.choice"
408
+ - "telemetry:juggle:goal.detected"
409
+ - "telemetry:mechanic:episode.timer"
410
+ - "telemetry:match:dilemma:current"
409
411
  note: |
410
- $id in signal file: NO "telemetry:" prefix (e.g., commons:ux:foundations:color.metric.be.count)
411
- URN in wagon manifests: WITH "telemetry:" prefix (e.g., telemetry:commons:ux:foundations)
412
- artifact_ref: WITH "contract:" prefix (e.g., contract:commons:ux:foundations:color)
412
+ $id in signal file: NO "telemetry:" prefix (e.g., mechanic:decision.choice.event.be)
413
+ URN in wagon manifests: WITH "telemetry:" prefix (e.g., telemetry:mechanic:decision.choice)
414
+ artifact_ref: WITH "contract:" prefix (e.g., contract:mechanic:decision.choice)
413
415
 
414
- Hierarchy (colons) for path segments, dots for signal facets (type.plane.measure).
415
- Mirrors contract structure perfectly.
416
+ Hierarchy (colons) for path segments, dots for:
417
+ - Variants in URN (e.g., decision.choice, goal.detected)
418
+ - Signal facets in $id (type.plane.measure)
419
+
420
+ Aligns with artifact-naming.convention.yaml separator semantics.
416
421
 
417
422
  Examples:
418
423
  File: telemetry/commons/ux/foundations/color.metric.be.count.json
@@ -421,19 +426,19 @@ tracking_structure:
421
426
  artifact_ref: contract:commons:ux:foundations:color
422
427
 
423
428
  urn_path_mapping:
424
- pattern: "telemetry:{theme}(:{path})*:{aspect} (wagon manifest format)"
429
+ pattern: "telemetry:{theme}(:{path})*:{aspect}(.{variant})? (wagon manifest format)"
425
430
  path_construction:
426
- directory: "telemetry/{theme}/{path}/{aspect}/"
427
- filename: "{resource}.{type}.{plane}[.{measure}].json"
431
+ directory: "telemetry/{theme}/{path}/"
432
+ filename: "{aspect}[.{variant}].{type}.{plane}[.{measure}].json"
428
433
  round_trip: "URN ↔ path must be identity transformation"
429
- note: "Directory structure mirrors contracts exactly - aspect is subdirectory, resource is filename prefix"
434
+ note: "Directory structure mirrors contracts. Dot notation allowed for variants in URN."
430
435
  comparison:
431
- contract_path: "contracts/commons/ux/foundations/color.schema.json"
432
- contract_id: "commons:ux:foundations:color"
433
- contract_urn: "contract:commons:ux:foundations:color"
434
- telemetry_path: "telemetry/commons/ux/foundations/color.metric.be.count.json"
435
- telemetry_id: "commons:ux:foundations:color.metric.be.count"
436
- telemetry_urn: "telemetry:commons:ux:foundations"
436
+ contract_path: "contracts/mechanic/decision/choice.schema.json"
437
+ contract_id: "mechanic:decision.choice"
438
+ contract_urn: "contract:mechanic:decision.choice"
439
+ telemetry_path: "telemetry/mechanic/decision/choice.event.be.json"
440
+ telemetry_id: "mechanic:decision.choice.event.be"
441
+ telemetry_urn: "telemetry:mechanic:decision.choice"
437
442
 
438
443
  artifact_naming_grammar:
439
444
  pattern: "{theme}:{domain}:{aspect}"
@@ -2,7 +2,7 @@
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "$id": "telemetry-tracking-manifest-schema",
4
4
  "title": "Telemetry Tracking Manifest Schema",
5
- "description": "Schema for telemetry/_tracking.yaml manifest file",
5
+ "description": "Schema for telemetry/_taxonomy.yaml manifest file",
6
6
  "type": "object",
7
7
  "required": ["version", "planes", "measures", "artifacts"],
8
8
  "properties": {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: atdd
3
- Version: 0.7.1
3
+ Version: 0.7.2
4
4
  Summary: ATDD Platform - Acceptance Test Driven Development toolkit
5
5
  License: MIT
6
6
  Requires-Python: >=3.10
@@ -14,21 +14,22 @@ atdd/coach/commands/initializer.py,sha256=wuvzj7QwA11ilNjRZU6Bx2bLQXITdBHJxR9_mZ
14
14
  atdd/coach/commands/interface.py,sha256=FwBrJpWkfSL9n4n0HT_EC-alseXgU0bweKD4TImyHN0,40483
15
15
  atdd/coach/commands/inventory.py,sha256=hI8JwG7Ph-jBhd5a8j3kwDMJVvFjzq8A0Zpt8TYEHXI,24976
16
16
  atdd/coach/commands/migration.py,sha256=wRxU7emvvHqWt1MvXKkNTkPBjp0sU9g8F5Uy5yV2YfI,8177
17
- atdd/coach/commands/registry.py,sha256=9iWW34CCJAr36v91863u8TDdlGQJdLpYYBGb1ojtS1Q,71546
17
+ atdd/coach/commands/registry.py,sha256=Ri2X5AqzojNokxP5-yb3nZj6nO9DsNT-68vgsSOmgg0,71558
18
18
  atdd/coach/commands/session.py,sha256=MhuWXd5TR6bB3w0t8vANeZx3L476qwLT6EUQMwg-wQA,14268
19
19
  atdd/coach/commands/sync.py,sha256=SLNzhcc6IuzMofMbkH9wM9rBSk5tPfcWPKXn9TaSZ-Y,13782
20
20
  atdd/coach/commands/test_interface.py,sha256=a7ut2Hhk0PnQ5LfJZkoQwfkfkVuB5OHA4QBwOS0-jcg,16870
21
21
  atdd/coach/commands/test_runner.py,sha256=_6JrDRq5fBHUOC4MtkgXcjkgJjG80otoGRTqnkEphIk,5832
22
- atdd/coach/commands/traceability.py,sha256=8TmpZDeUVHJAz-p3oxXq55jCFiFpKIQR8h1wLZVYcgA,163612
22
+ atdd/coach/commands/traceability.py,sha256=uB-QMM3MWvY2NSsMDubAN-vY0ddI1uJIRmHLqhZIR_E,163618
23
23
  atdd/coach/commands/tests/__init__.py,sha256=svBEnRruMuXuaYi3lFxJlzHNWdZ5vlBTaBpjXupaxDA,33
24
24
  atdd/coach/commands/tests/test_telemetry_array_validation.py,sha256=WK5ZXvR1avlzX7mSX84dmxxLFnw7eQB4jtjo7bHG7aE,8464
25
- atdd/coach/conventions/session.convention.yaml,sha256=1wCxQ_Y2Wb2080Xt2JZs0_WsV8_4SC0Tq87G_BCGdiE,26049
25
+ atdd/coach/conventions/naming.convention.yaml,sha256=GHqymDducgMxcMmSUwoKE6xXGEv8AENodWgAzcS7o60,11191
26
+ atdd/coach/conventions/session.convention.yaml,sha256=Z4hCFNjOizgDXTRVqNZ4VaG40TIFF31zDkMZdA-xrvI,26084
26
27
  atdd/coach/overlays/__init__.py,sha256=2lMiMSgfLJ3YHLpbzNI5B88AdQxiMEwjIfsWWb8t3To,123
27
28
  atdd/coach/overlays/claude.md,sha256=33mhpqhmsRhCtdWlU7cMXAJDsaVra9uBBK8URV8OtQA,101
28
29
  atdd/coach/schemas/config.schema.json,sha256=47cFGE5juBv9ewhtgrNir4b6I9imIIo8VjoD9yvASf4,4578
29
30
  atdd/coach/schemas/manifest.schema.json,sha256=WO13-YF_FgH1awh96khCtk-112b6XSC24anlY3B7GjY,2885
30
- atdd/coach/templates/ATDD.md,sha256=h_oPpKLX7nuafC0VAoKCnkM2-kGQeksR34QWlGyfMwU,13236
31
- atdd/coach/templates/SESSION-TEMPLATE.md,sha256=cGT_0x5KLbPHOCiuM8evLGpWKIlR-aggqxiBtbjSJoo,9478
31
+ atdd/coach/templates/ATDD.md,sha256=JTSPm-J2Xr6XfPodDCxnVyrKoMf2eHF2rlFw8ft6RLQ,13277
32
+ atdd/coach/templates/SESSION-TEMPLATE.md,sha256=uuvSR-OBVb1QrmU5HcS0iO9ohng0o2nVg-qaAe76HY4,9894
32
33
  atdd/coach/utils/__init__.py,sha256=7Jbo-heJEKSAn6I0s35z_2S4R8qGZ48PL6a2IntcNYg,148
33
34
  atdd/coach/utils/config.py,sha256=6XXaaeVfjTrJwdaR0IZ6Kf1-1ZHhaCVLO5pNx_A2el4,3320
34
35
  atdd/coach/utils/coverage_phase.py,sha256=14CzGiTEeb-Z-CMYnJjx1-4dn3LbQVJUlFr_-1bKVMc,3250
@@ -108,7 +109,7 @@ atdd/planner/conventions/criteria.convention.yaml,sha256=twQElTZEu5hGN5blDE66OUx
108
109
  atdd/planner/conventions/feature.convention.yaml,sha256=Jksi04E2h8PaUBbjR1GLKMXf-ec9MJrUcOK2lJC2hjg,11324
109
110
  atdd/planner/conventions/interface.convention.yaml,sha256=NBWlIbXuwYtmxkc20zzzgFOs43v9ID6V3b82drrzQ3c,16323
110
111
  atdd/planner/conventions/steps.convention.yaml,sha256=DkRry5s0I85BuEmrF7N1VhInZPeE-pRLbJ0zPYSWyY0,6804
111
- atdd/planner/conventions/train.convention.yaml,sha256=XlHGpKbSBqqdKSNr17RnqmKi9j5hBYLVQQtxSsnsRzE,19454
112
+ atdd/planner/conventions/train.convention.yaml,sha256=5WiODngpAhL7FJcHxXooIjkFJ3zVOn5OG_qK4w2o2IU,20303
112
113
  atdd/planner/conventions/wagon.convention.yaml,sha256=0qC0utZGH1cN07Jo5O2gZg-XFQgT1q23zxsHxjkFuz4,11093
113
114
  atdd/planner/conventions/wmbt.convention.yaml,sha256=p8kvWR8rqYzQaY3J_BToxaI06Vaa96wM4CR_VP_Y4hc,14393
114
115
  atdd/planner/schemas/acceptance.schema.json,sha256=3mQV067ipiYsTcXkDll4zWJBYdOkB_Y3kApV7byjdxs,11889
@@ -125,7 +126,7 @@ atdd/planner/validators/test_hierarchy_coverage.py,sha256=7NG_2GL4B-CQKHAHxTHxCv
125
126
  atdd/planner/validators/test_plan_cross_refs.py,sha256=kxlq1uZ2u4mn3r8wHJjXVJsB8nmzwsvSzOlRapJ9pBY,9520
126
127
  atdd/planner/validators/test_plan_uniqueness.py,sha256=rlC5khAoBkgpTZJdyHi1JbDUj14v1JiGBFv2iV_AP_Y,7735
127
128
  atdd/planner/validators/test_plan_urn_resolution.py,sha256=GoxFiRjOfp69FUmIyKGnsGgpYalOz3qfp6qjyCkga44,9440
128
- atdd/planner/validators/test_plan_wagons.py,sha256=l4jbHf9Kg-Fy8Gz5O8BO7PDQKbbeLN0uctoErPK_YKI,7357
129
+ atdd/planner/validators/test_plan_wagons.py,sha256=fFK34Ul1dg7fuz0t2BmncEWudDknyQ8ftp_NdNez2pQ,10232
129
130
  atdd/planner/validators/test_train_validation.py,sha256=7vlu3P8PenWgZhZCf9kO0UTM-k1n37Ds_jUvrJa-Np0,39264
130
131
  atdd/planner/validators/test_wagon_urn_chain.py,sha256=KY_0vrj6CoiQJ80WbqfCGCYbup13cVssaxbNO0eVf74,26697
131
132
  atdd/planner/validators/test_wmbt_consistency.py,sha256=jdfu4xWEozzBGwplKDXxuDQNLBDxB_AC96NHLkyHqQ8,10875
@@ -139,7 +140,7 @@ atdd/tester/conventions/migration.convention.yaml,sha256=Xx5EIwNct6wb--sYtm7EJp8
139
140
  atdd/tester/conventions/red.convention.yaml,sha256=S0mc4JpvNuOSYhqmt6bm0tCuDTCFYFRsSBru3XMwXgs,28901
140
141
  atdd/tester/conventions/routing.convention.yaml,sha256=gRJrnQd-cXCUGby0CeaJdRmrFXZx70kl-FxXCoXiu5Y,2751
141
142
  atdd/tester/conventions/security.convention.yaml,sha256=3QjQZqw1Iw8g6jUmuKWkOqcZ1n1sc1OJDvKD0eTk070,5445
142
- atdd/tester/conventions/telemetry.convention.yaml,sha256=n8Q8x7BtiDnDf920EWiq3xBzaf8tYev7WIi1pQ27O6o,16119
143
+ atdd/tester/conventions/telemetry.convention.yaml,sha256=B1-j4jqPenXVrKBrYaiWy8sAP0VgbJyC5LRLXmzDdeg,16260
143
144
  atdd/tester/schemas/a11y.tmpl.json,sha256=o-i8-fQeLxqTPgeDysOQDvyoHdlcCDOlUGtPG1-_Wro,1088
144
145
  atdd/tester/schemas/artifact.schema.json,sha256=CVmhmz9dsSsZW4HYS_wohn-kzq_mx4YPYunwrBHtbQg,5755
145
146
  atdd/tester/schemas/contract.schema.json,sha256=2fHyVeLzFUkdQuWGxt3gdxblIPFTB0tkmHUYUYdcf-E,19639
@@ -160,7 +161,7 @@ atdd/tester/schemas/script.tmpl.json,sha256=VML3qBtWX6giG1yXZSDpgAoPHWzm8UkFUO0a
160
161
  atdd/tester/schemas/sec.tmpl.json,sha256=XIahZQMd128nmpvTPC6TXgOqrwHsGnS-qhkORMo7gGE,909
161
162
  atdd/tester/schemas/storage.tmpl.json,sha256=BLGzhrvt79x2zjmhml8L01AlBj0xsCtuqIlF_aQAuw0,1038
162
163
  atdd/tester/schemas/telemetry.schema.json,sha256=dJjKM66uur032rUTkzxEwtpfVS5njI83wCIzbrE_Vo4,3319
163
- atdd/tester/schemas/telemetry_tracking_manifest.schema.json,sha256=hw844n-k5SCOfzTPhIwYWV4tT8z-bxhby6ILUZknNao,3846
164
+ atdd/tester/schemas/telemetry_tracking_manifest.schema.json,sha256=uFibjN6V-GHK45tz5ZXs4z3kjcjJa9A_AalNdu-1jyI,3846
164
165
  atdd/tester/schemas/test_filename.schema.json,sha256=-kzKAyeXhgNc7J1W35HmubbOi1_YPpEruT30wZLQe_U,6717
165
166
  atdd/tester/schemas/test_intent.schema.json,sha256=4gt0We9rwoQXF0p1TSY3eC37BMmM-MR8-BOA4tlO22o,5206
166
167
  atdd/tester/schemas/unit.tmpl.json,sha256=dWxUT2zWdvg1GRyMcSY-J_EBs0yCSu9F0cmuh6rtBXs,823
@@ -200,9 +201,9 @@ atdd/tester/validators/test_train_frontend_e2e.py,sha256=fpfUwTbAWzuqxbVKoaFw-ab
200
201
  atdd/tester/validators/test_train_frontend_python.py,sha256=KK2U3oNFWLyBK7YHC0fU7shR05k93gVcO762AI8Q3pw,9018
201
202
  atdd/tester/validators/test_typescript_test_naming.py,sha256=E-TyGv_GVlTfsbyuxrtv9sOWSZS_QcpH6rrJFbWoeeU,11280
202
203
  atdd/tester/validators/test_typescript_test_structure.py,sha256=eV89SD1RaKtchBZupqhnJmaruoROosf3LwB4Fwe4UJI,2612
203
- atdd-0.7.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
204
- atdd-0.7.1.dist-info/METADATA,sha256=3Q4dTLPHmItb-Xjz2xAl2fDFlu0q97a4-hE7fDiY18w,8716
205
- atdd-0.7.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
206
- atdd-0.7.1.dist-info/entry_points.txt,sha256=-C3yrA1WQQfN3iuGmSzPapA5cKVBEYU5Q1HUffSJTbY,38
207
- atdd-0.7.1.dist-info/top_level.txt,sha256=VKkf6Uiyrm4RS6ULCGM-v8AzYN8K2yg8SMqwJLoO-xs,5
208
- atdd-0.7.1.dist-info/RECORD,,
204
+ atdd-0.7.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
205
+ atdd-0.7.2.dist-info/METADATA,sha256=_Rvqn06owPOazCQlN34cO_5tPLWZipNsRU0yfUABKrU,8716
206
+ atdd-0.7.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
207
+ atdd-0.7.2.dist-info/entry_points.txt,sha256=-C3yrA1WQQfN3iuGmSzPapA5cKVBEYU5Q1HUffSJTbY,38
208
+ atdd-0.7.2.dist-info/top_level.txt,sha256=VKkf6Uiyrm4RS6ULCGM-v8AzYN8K2yg8SMqwJLoO-xs,5
209
+ atdd-0.7.2.dist-info/RECORD,,
File without changes