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.
- atdd/__init__.py +0 -0
- atdd/cli.py +404 -0
- atdd/coach/__init__.py +0 -0
- atdd/coach/commands/__init__.py +0 -0
- atdd/coach/commands/add_persistence_metadata.py +215 -0
- atdd/coach/commands/analyze_migrations.py +188 -0
- atdd/coach/commands/consumers.py +720 -0
- atdd/coach/commands/infer_governance_status.py +149 -0
- atdd/coach/commands/initializer.py +177 -0
- atdd/coach/commands/interface.py +1078 -0
- atdd/coach/commands/inventory.py +565 -0
- atdd/coach/commands/migration.py +240 -0
- atdd/coach/commands/registry.py +1560 -0
- atdd/coach/commands/session.py +430 -0
- atdd/coach/commands/sync.py +405 -0
- atdd/coach/commands/test_interface.py +399 -0
- atdd/coach/commands/test_runner.py +141 -0
- atdd/coach/commands/tests/__init__.py +1 -0
- atdd/coach/commands/tests/test_telemetry_array_validation.py +235 -0
- atdd/coach/commands/traceability.py +4264 -0
- atdd/coach/conventions/session.convention.yaml +754 -0
- atdd/coach/overlays/__init__.py +2 -0
- atdd/coach/overlays/claude.md +2 -0
- atdd/coach/schemas/config.schema.json +34 -0
- atdd/coach/schemas/manifest.schema.json +101 -0
- atdd/coach/templates/ATDD.md +282 -0
- atdd/coach/templates/SESSION-TEMPLATE.md +327 -0
- atdd/coach/utils/__init__.py +0 -0
- atdd/coach/utils/graph/__init__.py +0 -0
- atdd/coach/utils/graph/urn.py +875 -0
- atdd/coach/validators/__init__.py +0 -0
- atdd/coach/validators/shared_fixtures.py +365 -0
- atdd/coach/validators/test_enrich_wagon_registry.py +167 -0
- atdd/coach/validators/test_registry.py +575 -0
- atdd/coach/validators/test_session_validation.py +1183 -0
- atdd/coach/validators/test_traceability.py +448 -0
- atdd/coach/validators/test_update_feature_paths.py +108 -0
- atdd/coach/validators/test_validate_contract_consumers.py +297 -0
- atdd/coder/__init__.py +1 -0
- atdd/coder/conventions/adapter.recipe.yaml +88 -0
- atdd/coder/conventions/backend.convention.yaml +460 -0
- atdd/coder/conventions/boundaries.convention.yaml +666 -0
- atdd/coder/conventions/commons.convention.yaml +460 -0
- atdd/coder/conventions/complexity.recipe.yaml +109 -0
- atdd/coder/conventions/component-naming.convention.yaml +178 -0
- atdd/coder/conventions/design.convention.yaml +327 -0
- atdd/coder/conventions/design.recipe.yaml +273 -0
- atdd/coder/conventions/dto.convention.yaml +660 -0
- atdd/coder/conventions/frontend.convention.yaml +542 -0
- atdd/coder/conventions/green.convention.yaml +1012 -0
- atdd/coder/conventions/presentation.convention.yaml +587 -0
- atdd/coder/conventions/refactor.convention.yaml +535 -0
- atdd/coder/conventions/technology.convention.yaml +206 -0
- atdd/coder/conventions/tests/__init__.py +0 -0
- atdd/coder/conventions/tests/test_adapter_recipe.py +302 -0
- atdd/coder/conventions/tests/test_complexity_recipe.py +289 -0
- atdd/coder/conventions/tests/test_component_taxonomy.py +278 -0
- atdd/coder/conventions/tests/test_component_urn_naming.py +165 -0
- atdd/coder/conventions/tests/test_thinness_recipe.py +286 -0
- atdd/coder/conventions/thinness.recipe.yaml +82 -0
- atdd/coder/conventions/train.convention.yaml +325 -0
- atdd/coder/conventions/verification.protocol.yaml +53 -0
- atdd/coder/schemas/design_system.schema.json +361 -0
- atdd/coder/validators/__init__.py +0 -0
- atdd/coder/validators/test_commons_structure.py +485 -0
- atdd/coder/validators/test_complexity.py +416 -0
- atdd/coder/validators/test_cross_language_consistency.py +431 -0
- atdd/coder/validators/test_design_system_compliance.py +413 -0
- atdd/coder/validators/test_dto_testing_patterns.py +268 -0
- atdd/coder/validators/test_green_cross_stack_layers.py +168 -0
- atdd/coder/validators/test_green_layer_dependencies.py +148 -0
- atdd/coder/validators/test_green_python_layer_structure.py +103 -0
- atdd/coder/validators/test_green_supabase_layer_structure.py +103 -0
- atdd/coder/validators/test_import_boundaries.py +396 -0
- atdd/coder/validators/test_init_file_urns.py +593 -0
- atdd/coder/validators/test_preact_layer_boundaries.py +221 -0
- atdd/coder/validators/test_presentation_convention.py +260 -0
- atdd/coder/validators/test_python_architecture.py +674 -0
- atdd/coder/validators/test_quality_metrics.py +420 -0
- atdd/coder/validators/test_station_master_pattern.py +244 -0
- atdd/coder/validators/test_train_infrastructure.py +454 -0
- atdd/coder/validators/test_train_urns.py +293 -0
- atdd/coder/validators/test_typescript_architecture.py +616 -0
- atdd/coder/validators/test_usecase_structure.py +421 -0
- atdd/coder/validators/test_wagon_boundaries.py +586 -0
- atdd/conftest.py +126 -0
- atdd/planner/__init__.py +1 -0
- atdd/planner/conventions/acceptance.convention.yaml +538 -0
- atdd/planner/conventions/appendix.convention.yaml +187 -0
- atdd/planner/conventions/artifact-naming.convention.yaml +852 -0
- atdd/planner/conventions/component.convention.yaml +670 -0
- atdd/planner/conventions/criteria.convention.yaml +141 -0
- atdd/planner/conventions/feature.convention.yaml +371 -0
- atdd/planner/conventions/interface.convention.yaml +382 -0
- atdd/planner/conventions/steps.convention.yaml +141 -0
- atdd/planner/conventions/train.convention.yaml +552 -0
- atdd/planner/conventions/wagon.convention.yaml +275 -0
- atdd/planner/conventions/wmbt.convention.yaml +258 -0
- atdd/planner/schemas/acceptance.schema.json +336 -0
- atdd/planner/schemas/appendix.schema.json +78 -0
- atdd/planner/schemas/component.schema.json +114 -0
- atdd/planner/schemas/feature.schema.json +197 -0
- atdd/planner/schemas/train.schema.json +192 -0
- atdd/planner/schemas/wagon.schema.json +281 -0
- atdd/planner/schemas/wmbt.schema.json +59 -0
- atdd/planner/validators/__init__.py +0 -0
- atdd/planner/validators/conftest.py +5 -0
- atdd/planner/validators/test_draft_wagon_registry.py +374 -0
- atdd/planner/validators/test_plan_cross_refs.py +240 -0
- atdd/planner/validators/test_plan_uniqueness.py +224 -0
- atdd/planner/validators/test_plan_urn_resolution.py +268 -0
- atdd/planner/validators/test_plan_wagons.py +174 -0
- atdd/planner/validators/test_train_validation.py +514 -0
- atdd/planner/validators/test_wagon_urn_chain.py +648 -0
- atdd/planner/validators/test_wmbt_consistency.py +327 -0
- atdd/planner/validators/test_wmbt_vocabulary.py +632 -0
- atdd/tester/__init__.py +1 -0
- atdd/tester/conventions/artifact.convention.yaml +257 -0
- atdd/tester/conventions/contract.convention.yaml +1009 -0
- atdd/tester/conventions/filename.convention.yaml +555 -0
- atdd/tester/conventions/migration.convention.yaml +509 -0
- atdd/tester/conventions/red.convention.yaml +797 -0
- atdd/tester/conventions/routing.convention.yaml +51 -0
- atdd/tester/conventions/telemetry.convention.yaml +458 -0
- atdd/tester/schemas/a11y.tmpl.json +17 -0
- atdd/tester/schemas/artifact.schema.json +189 -0
- atdd/tester/schemas/contract.schema.json +591 -0
- atdd/tester/schemas/contract.tmpl.json +95 -0
- atdd/tester/schemas/db.tmpl.json +20 -0
- atdd/tester/schemas/e2e.tmpl.json +17 -0
- atdd/tester/schemas/edge_function.tmpl.json +17 -0
- atdd/tester/schemas/event.tmpl.json +17 -0
- atdd/tester/schemas/http.tmpl.json +19 -0
- atdd/tester/schemas/job.tmpl.json +18 -0
- atdd/tester/schemas/load.tmpl.json +21 -0
- atdd/tester/schemas/metric.tmpl.json +19 -0
- atdd/tester/schemas/pack.schema.json +139 -0
- atdd/tester/schemas/realtime.tmpl.json +20 -0
- atdd/tester/schemas/rls.tmpl.json +18 -0
- atdd/tester/schemas/script.tmpl.json +16 -0
- atdd/tester/schemas/sec.tmpl.json +18 -0
- atdd/tester/schemas/storage.tmpl.json +18 -0
- atdd/tester/schemas/telemetry.schema.json +128 -0
- atdd/tester/schemas/telemetry_tracking_manifest.schema.json +143 -0
- atdd/tester/schemas/test_filename.schema.json +194 -0
- atdd/tester/schemas/test_intent.schema.json +179 -0
- atdd/tester/schemas/unit.tmpl.json +18 -0
- atdd/tester/schemas/visual.tmpl.json +18 -0
- atdd/tester/schemas/ws.tmpl.json +17 -0
- atdd/tester/utils/__init__.py +0 -0
- atdd/tester/utils/filename.py +300 -0
- atdd/tester/validators/__init__.py +0 -0
- atdd/tester/validators/cleanup_duplicate_headers.py +116 -0
- atdd/tester/validators/cleanup_duplicate_headers_v2.py +135 -0
- atdd/tester/validators/conftest.py +5 -0
- atdd/tester/validators/coverage_gap_report.py +321 -0
- atdd/tester/validators/fix_dual_ac_references.py +179 -0
- atdd/tester/validators/remove_duplicate_lines.py +93 -0
- atdd/tester/validators/test_acceptance_urn_filename_mapping.py +359 -0
- atdd/tester/validators/test_acceptance_urn_separator.py +166 -0
- atdd/tester/validators/test_artifact_naming_category.py +307 -0
- atdd/tester/validators/test_contract_schema_compliance.py +706 -0
- atdd/tester/validators/test_contracts_structure.py +200 -0
- atdd/tester/validators/test_coverage_adequacy.py +797 -0
- atdd/tester/validators/test_dual_ac_reference.py +225 -0
- atdd/tester/validators/test_fixture_validity.py +372 -0
- atdd/tester/validators/test_isolation.py +487 -0
- atdd/tester/validators/test_migration_coverage.py +204 -0
- atdd/tester/validators/test_migration_criteria.py +276 -0
- atdd/tester/validators/test_migration_generation.py +116 -0
- atdd/tester/validators/test_python_test_naming.py +410 -0
- atdd/tester/validators/test_red_layer_validation.py +95 -0
- atdd/tester/validators/test_red_python_layer_structure.py +87 -0
- atdd/tester/validators/test_red_supabase_layer_structure.py +90 -0
- atdd/tester/validators/test_telemetry_structure.py +634 -0
- atdd/tester/validators/test_typescript_test_naming.py +301 -0
- atdd/tester/validators/test_typescript_test_structure.py +84 -0
- atdd-0.1.0.dist-info/METADATA +191 -0
- atdd-0.1.0.dist-info/RECORD +183 -0
- atdd-0.1.0.dist-info/WHEEL +5 -0
- atdd-0.1.0.dist-info/entry_points.txt +2 -0
- atdd-0.1.0.dist-info/licenses/LICENSE +674 -0
- atdd-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,670 @@
|
|
|
1
|
+
version: "1.0"
|
|
2
|
+
name: "Component Convention"
|
|
3
|
+
description: "Rules for deriving components from feature details with business capability focus"
|
|
4
|
+
|
|
5
|
+
# URN naming pattern
|
|
6
|
+
urn_naming:
|
|
7
|
+
pattern: "component:{wagon}:{feature}[.{objectCamelCase}][.{side}][.{layer}]"
|
|
8
|
+
description: "Stable component URN: hierarchy via colons (kind:wagon:feature), optional facets via dots."
|
|
9
|
+
utility: "utils.graph.URNBuilder.component(wagon_id, feature_id, component_name?, side?, layer?)"
|
|
10
|
+
|
|
11
|
+
parts:
|
|
12
|
+
wagon: "Parent wagon identifier (kebab-case), e.g., resolve-dilemmas"
|
|
13
|
+
feature: "Parent feature identifier (kebab-case), e.g., choose-option"
|
|
14
|
+
objectCamelCase: "Logical component name (PascalCase or camelCase), e.g., OptionValidator"
|
|
15
|
+
side: "Deployment side (frontend|backend)"
|
|
16
|
+
layer: "Architectural layer (presentation|application|domain|integration)"
|
|
17
|
+
|
|
18
|
+
rules:
|
|
19
|
+
hierarchy_separator: ":"
|
|
20
|
+
facet_separator: "."
|
|
21
|
+
casing:
|
|
22
|
+
wagon_feature: "^[a-z][a-z0-9-]*$"
|
|
23
|
+
facets:
|
|
24
|
+
- "^[a-z][a-z0-9-]*$" # kebab/lower facet allowed
|
|
25
|
+
- "^[A-Z][a-zA-Z0-9]*$" # CamelCase facet allowed
|
|
26
|
+
no_file_extensions: "Do not include .py/.dart/etc. Use a 'lang-*' facet if needed."
|
|
27
|
+
case_policy: "IDs are case-sensitive; store exactly as written."
|
|
28
|
+
|
|
29
|
+
lint_regex: "^component:[a-z][a-z0-9-]*:[a-z][a-z0-9-]*\.[A-Z][a-zA-Z0-9]*\.(frontend|backend)\.(presentation|application|domain|integration)$"
|
|
30
|
+
|
|
31
|
+
examples:
|
|
32
|
+
- urn: "component:resolve-dilemmas:choose-option.OptionValidator.backend.domain"
|
|
33
|
+
wagon: "resolve-dilemmas"
|
|
34
|
+
feature: "choose-option"
|
|
35
|
+
component: "OptionValidator"
|
|
36
|
+
side: "backend"
|
|
37
|
+
layer: "domain"
|
|
38
|
+
|
|
39
|
+
- urn: "component:manage-users:authenticate-user.LoginForm.frontend.presentation"
|
|
40
|
+
wagon: "manage-users"
|
|
41
|
+
feature: "authenticate-user"
|
|
42
|
+
component: "LoginForm"
|
|
43
|
+
side: "frontend"
|
|
44
|
+
layer: "presentation"
|
|
45
|
+
|
|
46
|
+
- urn: "component:maintain-ux:assets-catalog.AssetIndexer.backend.integration"
|
|
47
|
+
wagon: "maintain-ux"
|
|
48
|
+
feature: "assets-catalog"
|
|
49
|
+
component: "AssetIndexer"
|
|
50
|
+
side: "backend"
|
|
51
|
+
layer: "integration"
|
|
52
|
+
|
|
53
|
+
note: "Side and layer values are defined by component_type_catalog structure below"
|
|
54
|
+
|
|
55
|
+
# Component type catalog from coder conventions with complexity weights
|
|
56
|
+
component_type_catalog:
|
|
57
|
+
description: "Canonical catalog of all component types from coder conventions with weights"
|
|
58
|
+
source: "Derived from .claude/conventions/coder/{backend,frontend}.convention.yaml"
|
|
59
|
+
|
|
60
|
+
backend:
|
|
61
|
+
presentation:
|
|
62
|
+
controllers:
|
|
63
|
+
suffix: {python: "*_controller.py", typescript: "*-controller.ts"}
|
|
64
|
+
description: "Request/response handlers for external interfaces"
|
|
65
|
+
weight: 1
|
|
66
|
+
routes:
|
|
67
|
+
suffix: {python: "*_routes.py", typescript: "*-routes.ts"}
|
|
68
|
+
description: "Routing configuration and endpoint definitions"
|
|
69
|
+
weight: 0
|
|
70
|
+
serializers:
|
|
71
|
+
suffix: {python: "*_serializer.py", typescript: "*-serializer.ts"}
|
|
72
|
+
description: "Input/output data serialization and formatting"
|
|
73
|
+
weight: 0.5
|
|
74
|
+
validators:
|
|
75
|
+
suffix: {python: "*_validator.py", typescript: "*-validator.ts"}
|
|
76
|
+
description: "Input validation at the edge"
|
|
77
|
+
weight: 0.5
|
|
78
|
+
middleware:
|
|
79
|
+
suffix: {python: "*_middleware.py", typescript: "*-middleware.ts"}
|
|
80
|
+
description: "Cross-cutting request/response processing"
|
|
81
|
+
weight: 1
|
|
82
|
+
guards:
|
|
83
|
+
suffix: {python: "*_guard.py", typescript: "*-guard.ts"}
|
|
84
|
+
description: "Authentication and authorization at transport layer"
|
|
85
|
+
weight: 1
|
|
86
|
+
views:
|
|
87
|
+
suffix: {python: "*_view.py", typescript: "*-view.ts"}
|
|
88
|
+
description: "Server-side rendered templates and UI components"
|
|
89
|
+
weight: 1
|
|
90
|
+
|
|
91
|
+
application:
|
|
92
|
+
use_cases:
|
|
93
|
+
suffix: {python: "*_use_case.py", typescript: "*-use-case.ts"}
|
|
94
|
+
description: "Application-specific business workflows"
|
|
95
|
+
weight: 2
|
|
96
|
+
handlers:
|
|
97
|
+
suffix: {python: "*_handler.py", typescript: "*-handler.ts"}
|
|
98
|
+
description: "Command, query, and event processing"
|
|
99
|
+
weight: 1
|
|
100
|
+
ports:
|
|
101
|
+
suffix: {python: "protocols.py, *_port.py", typescript: "*-port.ts"}
|
|
102
|
+
description: "Interfaces and protocols for integration layer"
|
|
103
|
+
weight: 0
|
|
104
|
+
dtos:
|
|
105
|
+
suffix: {python: "*_dto.py", typescript: "*-dto.ts"}
|
|
106
|
+
description: "Data transfer objects between layers"
|
|
107
|
+
weight: 0
|
|
108
|
+
policies:
|
|
109
|
+
suffix: {python: "*_policy.py", typescript: "*-policy.ts"}
|
|
110
|
+
description: "Application-level business policies and rules"
|
|
111
|
+
weight: 1
|
|
112
|
+
workflows:
|
|
113
|
+
suffix: {python: "*_workflow.py, *_saga.py", typescript: "*-workflow.ts"}
|
|
114
|
+
description: "Long-running processes and orchestrations"
|
|
115
|
+
weight: 2
|
|
116
|
+
|
|
117
|
+
domain:
|
|
118
|
+
entities:
|
|
119
|
+
suffix: {python: "*.py", typescript: "*.ts"}
|
|
120
|
+
description: "Core business objects with identity and lifecycle"
|
|
121
|
+
weight: 1
|
|
122
|
+
value_objects:
|
|
123
|
+
suffix: {python: "*_vo.py, *.py", typescript: "*-vo.ts"}
|
|
124
|
+
description: "Immutable types with equality-by-value semantics"
|
|
125
|
+
weight: 0.5
|
|
126
|
+
aggregates:
|
|
127
|
+
suffix: {python: "*_aggregate.py", typescript: "*-aggregate.ts"}
|
|
128
|
+
description: "Transactional consistency boundaries"
|
|
129
|
+
weight: 2
|
|
130
|
+
services:
|
|
131
|
+
suffix: {python: "*_service.py", typescript: "*-service.ts"}
|
|
132
|
+
description: "Domain services for cross-entity business logic"
|
|
133
|
+
weight: 1
|
|
134
|
+
specifications:
|
|
135
|
+
suffix: {python: "*_spec.py", typescript: "*-spec.ts"}
|
|
136
|
+
description: "Composable business rules and predicates"
|
|
137
|
+
weight: 0.5
|
|
138
|
+
events:
|
|
139
|
+
suffix: {python: "*_event.py", typescript: "*-event.ts"}
|
|
140
|
+
description: "Domain events representing facts that happened"
|
|
141
|
+
weight: 0
|
|
142
|
+
exceptions:
|
|
143
|
+
suffix: {python: "*_exception.py", typescript: "*-exception.ts"}
|
|
144
|
+
description: "Domain-specific errors and invariant violations"
|
|
145
|
+
weight: 0
|
|
146
|
+
|
|
147
|
+
integration:
|
|
148
|
+
repositories:
|
|
149
|
+
suffix: {python: "*_repository.py", typescript: "*-repository.ts"}
|
|
150
|
+
description: "Data persistence and retrieval adapters"
|
|
151
|
+
weight: 2
|
|
152
|
+
clients:
|
|
153
|
+
suffix: {python: "*_client.py", typescript: "*-client.ts"}
|
|
154
|
+
description: "External API and service clients"
|
|
155
|
+
weight: 1
|
|
156
|
+
caches:
|
|
157
|
+
suffix: {python: "*_cache.py", typescript: "*-cache.ts"}
|
|
158
|
+
description: "Caching implementations"
|
|
159
|
+
weight: 0.5
|
|
160
|
+
engines:
|
|
161
|
+
suffix: {python: "*_engine.py", typescript: "*-engine.ts"}
|
|
162
|
+
description: "Computational and processing engines (ML, graph, optimization)"
|
|
163
|
+
weight: 3
|
|
164
|
+
formatters:
|
|
165
|
+
suffix: {python: "*_formatter.py", typescript: "*-formatter.ts"}
|
|
166
|
+
description: "Output formatting and rendering services"
|
|
167
|
+
weight: 1
|
|
168
|
+
notifiers:
|
|
169
|
+
suffix: {python: "*_notifier.py", typescript: "*-notifier.ts"}
|
|
170
|
+
description: "Communication and notification services"
|
|
171
|
+
weight: 1
|
|
172
|
+
queues:
|
|
173
|
+
suffix: {python: "*_queue.py", typescript: "*-queue.ts"}
|
|
174
|
+
description: "Message queue and event streaming clients"
|
|
175
|
+
weight: 2
|
|
176
|
+
stores:
|
|
177
|
+
suffix: {python: "*_store.py", typescript: "*-store.ts"}
|
|
178
|
+
description: "File and object storage adapters"
|
|
179
|
+
weight: 1
|
|
180
|
+
mappers:
|
|
181
|
+
suffix: {python: "*_mapper.py", typescript: "*-mapper.ts"}
|
|
182
|
+
description: "Data transformation and mapping between layers"
|
|
183
|
+
weight: 0.5
|
|
184
|
+
schedulers:
|
|
185
|
+
suffix: {python: "*_scheduler.py", typescript: "*-scheduler.ts"}
|
|
186
|
+
description: "Background tasks and scheduled jobs"
|
|
187
|
+
weight: 2
|
|
188
|
+
monitors:
|
|
189
|
+
suffix: {python: "*_monitor.py", typescript: "*-monitor.ts"}
|
|
190
|
+
description: "Observability and infrastructure monitoring"
|
|
191
|
+
weight: 1
|
|
192
|
+
|
|
193
|
+
frontend:
|
|
194
|
+
presentation:
|
|
195
|
+
views:
|
|
196
|
+
suffix: {dart: "*_page.dart", typescript: "*-page.tsx"}
|
|
197
|
+
description: "Full-screen views and pages"
|
|
198
|
+
weight: 1
|
|
199
|
+
components:
|
|
200
|
+
suffix: {dart: "*_widget.dart", typescript: "*.tsx"}
|
|
201
|
+
description: "Reusable UI components"
|
|
202
|
+
weight: 0.5
|
|
203
|
+
containers:
|
|
204
|
+
suffix: {typescript: "*-container.tsx"}
|
|
205
|
+
description: "Smart components connected to state"
|
|
206
|
+
weight: 1
|
|
207
|
+
controllers:
|
|
208
|
+
suffix: {dart: "*_bloc.dart", typescript: "*-store.ts"}
|
|
209
|
+
description: "UI state management and business logic"
|
|
210
|
+
weight: 2
|
|
211
|
+
routes:
|
|
212
|
+
suffix: {dart: "*_router.dart", typescript: "*-routes.ts"}
|
|
213
|
+
description: "Navigation and routing configuration"
|
|
214
|
+
weight: 0
|
|
215
|
+
layouts:
|
|
216
|
+
suffix: {dart: "*_layout.dart", typescript: "*-layout.tsx"}
|
|
217
|
+
description: "Page structure and composition templates"
|
|
218
|
+
weight: 1
|
|
219
|
+
styles:
|
|
220
|
+
suffix: {dart: "*_theme.dart", typescript: "*.css"}
|
|
221
|
+
description: "Design tokens, themes, and styling"
|
|
222
|
+
weight: 0
|
|
223
|
+
animations:
|
|
224
|
+
suffix: {dart: "*_animation.dart", typescript: "*-animation.ts"}
|
|
225
|
+
description: "UI animations and transitions"
|
|
226
|
+
weight: 0.5
|
|
227
|
+
forms:
|
|
228
|
+
suffix: {dart: "*_form.dart", typescript: "*-form.ts"}
|
|
229
|
+
description: "Form state management and validation"
|
|
230
|
+
weight: 1
|
|
231
|
+
hooks:
|
|
232
|
+
suffix: {typescript: "use-*.ts"}
|
|
233
|
+
description: "Reusable stateful logic (React-style)"
|
|
234
|
+
weight: 0.5
|
|
235
|
+
directives:
|
|
236
|
+
suffix: {typescript: "*-directive.ts"}
|
|
237
|
+
description: "Custom DOM/element behaviors (Vue/Angular)"
|
|
238
|
+
weight: 0.5
|
|
239
|
+
filters:
|
|
240
|
+
suffix: {typescript: "*-filter.ts"}
|
|
241
|
+
description: "Data formatting pipes/filters"
|
|
242
|
+
weight: 0.5
|
|
243
|
+
|
|
244
|
+
application:
|
|
245
|
+
use_cases:
|
|
246
|
+
suffix: {dart: "*_use_case.dart", typescript: "*-use-case.ts"}
|
|
247
|
+
description: "Frontend-initiated workflows"
|
|
248
|
+
weight: 2
|
|
249
|
+
ports:
|
|
250
|
+
suffix: {dart: "*_port.dart", typescript: "*-port.ts"}
|
|
251
|
+
description: "Interfaces for data access and external services"
|
|
252
|
+
weight: 0
|
|
253
|
+
policies:
|
|
254
|
+
suffix: {dart: "*_policy.dart", typescript: "*-policy.ts"}
|
|
255
|
+
description: "Frontend business policies and rules"
|
|
256
|
+
weight: 1
|
|
257
|
+
dtos:
|
|
258
|
+
suffix: {dart: "*_dto.dart", typescript: "*-dto.ts"}
|
|
259
|
+
description: "Application-internal data structures"
|
|
260
|
+
weight: 0
|
|
261
|
+
|
|
262
|
+
domain:
|
|
263
|
+
entities:
|
|
264
|
+
suffix: {dart: "*.dart", typescript: "*.ts"}
|
|
265
|
+
description: "Domain models used on the client"
|
|
266
|
+
weight: 1
|
|
267
|
+
value_objects:
|
|
268
|
+
suffix: {dart: "*_vo.dart", typescript: "*-vo.ts"}
|
|
269
|
+
description: "Immutable typed values"
|
|
270
|
+
weight: 0.5
|
|
271
|
+
services:
|
|
272
|
+
suffix: {dart: "*_service.dart", typescript: "*-service.ts"}
|
|
273
|
+
description: "Pure domain logic services"
|
|
274
|
+
weight: 1
|
|
275
|
+
specifications:
|
|
276
|
+
suffix: {dart: "*_spec.dart", typescript: "*-spec.ts"}
|
|
277
|
+
description: "Composable rules and predicates"
|
|
278
|
+
weight: 0.5
|
|
279
|
+
exceptions:
|
|
280
|
+
suffix: {dart: "*_exception.dart", typescript: "*-exception.ts"}
|
|
281
|
+
description: "Domain-level errors"
|
|
282
|
+
weight: 0
|
|
283
|
+
|
|
284
|
+
integration:
|
|
285
|
+
repositories:
|
|
286
|
+
suffix: {dart: "*_repository.dart", typescript: "*-repository.ts"}
|
|
287
|
+
description: "Data access implementations"
|
|
288
|
+
weight: 2
|
|
289
|
+
clients:
|
|
290
|
+
suffix: {dart: "*_client.dart", typescript: "*-client.ts"}
|
|
291
|
+
description: "HTTP/WebSocket/GraphQL API clients"
|
|
292
|
+
weight: 1
|
|
293
|
+
stores:
|
|
294
|
+
suffix: {dart: "*_store.dart", typescript: "*-store.ts"}
|
|
295
|
+
description: "Local persistence implementations"
|
|
296
|
+
weight: 1
|
|
297
|
+
serializers:
|
|
298
|
+
suffix: {dart: "*_serializer.dart", typescript: "*-serializer.ts"}
|
|
299
|
+
description: "API data transformation"
|
|
300
|
+
weight: 0.5
|
|
301
|
+
mappers:
|
|
302
|
+
suffix: {dart: "*_mapper.dart", typescript: "*-mapper.ts"}
|
|
303
|
+
description: "Data transformation between layers"
|
|
304
|
+
weight: 0.5
|
|
305
|
+
interceptors:
|
|
306
|
+
suffix: {dart: "*_interceptor.dart", typescript: "*-interceptor.ts"}
|
|
307
|
+
description: "HTTP request/response middleware"
|
|
308
|
+
weight: 1
|
|
309
|
+
caches:
|
|
310
|
+
suffix: {dart: "*_cache.dart", typescript: "*-cache.ts"}
|
|
311
|
+
description: "Client-side caching implementations"
|
|
312
|
+
weight: 0.5
|
|
313
|
+
synchronizers:
|
|
314
|
+
suffix: {dart: "*_sync.dart", typescript: "*-sync.ts"}
|
|
315
|
+
description: "Offline sync and conflict resolution"
|
|
316
|
+
weight: 2
|
|
317
|
+
monitors:
|
|
318
|
+
suffix: {dart: "*_monitor.dart", typescript: "*-monitor.ts"}
|
|
319
|
+
description: "Client-side monitoring and telemetry"
|
|
320
|
+
weight: 1
|
|
321
|
+
validators:
|
|
322
|
+
suffix: {dart: "*_validator.dart", typescript: "*-validator.ts"}
|
|
323
|
+
description: "Client-side validation engines"
|
|
324
|
+
weight: 0.5
|
|
325
|
+
workers:
|
|
326
|
+
suffix: {typescript: "*.worker.ts"}
|
|
327
|
+
description: "Background processing and web workers"
|
|
328
|
+
weight: 2
|
|
329
|
+
connectors:
|
|
330
|
+
suffix: {dart: "*_connector.dart", typescript: "*-connector.ts"}
|
|
331
|
+
description: "Real-time and streaming connections"
|
|
332
|
+
weight: 1
|
|
333
|
+
|
|
334
|
+
# Artifact derivation for component naming
|
|
335
|
+
artifact_derivation:
|
|
336
|
+
description: "How to derive component names from artifact resources"
|
|
337
|
+
overview: |
|
|
338
|
+
Component names come from artifact resources (the part after colon).
|
|
339
|
+
Transform resource to PascalCase and add capability suffix based on artifact type.
|
|
340
|
+
Components describe CAPABILITY to handle artifacts.
|
|
341
|
+
|
|
342
|
+
rules:
|
|
343
|
+
pascalcase_conversion:
|
|
344
|
+
rule: "Convert artifact resource to PascalCase"
|
|
345
|
+
examples:
|
|
346
|
+
- from: "choice"
|
|
347
|
+
to: "Choice"
|
|
348
|
+
- from: "player-wallet"
|
|
349
|
+
to: "PlayerWallet"
|
|
350
|
+
- from: "domain-impacts"
|
|
351
|
+
to: "DomainImpacts"
|
|
352
|
+
- from: "remaining"
|
|
353
|
+
to: "Remaining"
|
|
354
|
+
|
|
355
|
+
capability_suffix:
|
|
356
|
+
rule: "Add capability suffix based on artifact type and component responsibility"
|
|
357
|
+
by_artifact_type:
|
|
358
|
+
events:
|
|
359
|
+
description: "Past tense resources (started, closed, credited)"
|
|
360
|
+
suffixes: ["Publisher", "Emitter", "Broadcaster"]
|
|
361
|
+
examples:
|
|
362
|
+
- artifact: "match:started"
|
|
363
|
+
resource: "started"
|
|
364
|
+
component: "MatchStartedPublisher"
|
|
365
|
+
urn: "component:resolve-dilemmas:make-choice.MatchStartedPublisher.backend.integration"
|
|
366
|
+
|
|
367
|
+
- artifact: "wallet:credited"
|
|
368
|
+
resource: "credited"
|
|
369
|
+
component: "WalletCreditedEmitter"
|
|
370
|
+
urn: "component:manage-wallets:credit-wallet.WalletCreditedEmitter.backend.integration"
|
|
371
|
+
|
|
372
|
+
states:
|
|
373
|
+
description: "Adjective resources (remaining, active, current)"
|
|
374
|
+
suffixes: ["Tracker", "Monitor", "Manager"]
|
|
375
|
+
examples:
|
|
376
|
+
- artifact: "mechanic:timebank.remaining"
|
|
377
|
+
resource: "remaining"
|
|
378
|
+
component: "TimebankTracker"
|
|
379
|
+
urn: "component:burn-timebank:track-timebank.TimebankTracker.backend.domain"
|
|
380
|
+
|
|
381
|
+
- artifact: "session:active"
|
|
382
|
+
resource: "active"
|
|
383
|
+
component: "SessionManager"
|
|
384
|
+
urn: "component:init-session:maintain-session.SessionManager.backend.application"
|
|
385
|
+
|
|
386
|
+
data:
|
|
387
|
+
description: "Noun resources (choice, identity, profile)"
|
|
388
|
+
suffixes: ["Provider", "Handler", "Processor", "Maker"]
|
|
389
|
+
examples:
|
|
390
|
+
- artifact: "mechanic:decision.choice"
|
|
391
|
+
resource: "choice"
|
|
392
|
+
component: "ChoiceMaker"
|
|
393
|
+
urn: "component:resolve-dilemmas:make-choice.ChoiceMaker.backend.domain"
|
|
394
|
+
|
|
395
|
+
- artifact: "player:identity"
|
|
396
|
+
resource: "identity"
|
|
397
|
+
component: "IdentityProvider"
|
|
398
|
+
urn: "component:contextualize-identity:identify-player.IdentityProvider.backend.application"
|
|
399
|
+
|
|
400
|
+
configs:
|
|
401
|
+
description: "Configuration resources (config, settings, agreement)"
|
|
402
|
+
suffixes: ["Configurator", "Builder", "Initializer"]
|
|
403
|
+
examples:
|
|
404
|
+
- artifact: "match:config"
|
|
405
|
+
resource: "config"
|
|
406
|
+
component: "MatchConfigurator"
|
|
407
|
+
urn: "component:setup-match:configure-match.MatchConfigurator.backend.application"
|
|
408
|
+
|
|
409
|
+
- artifact: "league:config"
|
|
410
|
+
resource: "config"
|
|
411
|
+
component: "LeagueBuilder"
|
|
412
|
+
urn: "component:define-league:configure-league.LeagueBuilder.backend.application"
|
|
413
|
+
|
|
414
|
+
layer_assignment:
|
|
415
|
+
description: "Assign components to layers based on artifact type and responsibility"
|
|
416
|
+
|
|
417
|
+
events:
|
|
418
|
+
typical_layers: ["integration", "application"]
|
|
419
|
+
rationale: "Event publishers at boundaries (external integration or internal application)"
|
|
420
|
+
examples:
|
|
421
|
+
- "MatchStartedPublisher → backend.integration (publishes to external systems)"
|
|
422
|
+
- "StateCommittedEmitter → backend.application (emits internal events)"
|
|
423
|
+
|
|
424
|
+
states:
|
|
425
|
+
typical_layers: ["domain", "application"]
|
|
426
|
+
rationale: "State trackers manage business state (domain) or coordinate (application)"
|
|
427
|
+
examples:
|
|
428
|
+
- "TimebankTracker → backend.domain (tracks core business state)"
|
|
429
|
+
- "SessionManager → backend.application (coordinates session lifecycle)"
|
|
430
|
+
|
|
431
|
+
data:
|
|
432
|
+
typical_layers: ["domain", "application", "integration"]
|
|
433
|
+
rationale: "Data handlers span layers based on responsibility"
|
|
434
|
+
examples:
|
|
435
|
+
- "ChoiceMaker → backend.domain (business logic for making choice)"
|
|
436
|
+
- "ChoiceHandler → backend.application (coordinates choice workflow)"
|
|
437
|
+
- "ChoicePersister → backend.integration (persists to database)"
|
|
438
|
+
|
|
439
|
+
configs:
|
|
440
|
+
typical_layers: ["application", "integration"]
|
|
441
|
+
rationale: "Configuration components coordinate setup or load settings"
|
|
442
|
+
examples:
|
|
443
|
+
- "MatchConfigurator → backend.application (coordinates match setup)"
|
|
444
|
+
- "ConfigLoader → backend.integration (loads from external config store)"
|
|
445
|
+
|
|
446
|
+
complete_example:
|
|
447
|
+
artifact: "mechanic:decision.choice"
|
|
448
|
+
wagon: "resolve-dilemmas"
|
|
449
|
+
feature: "make-choice"
|
|
450
|
+
components:
|
|
451
|
+
- name: "ChoiceDisplay"
|
|
452
|
+
urn: "component:resolve-dilemmas:make-choice.ChoiceDisplay.frontend.presentation"
|
|
453
|
+
purpose: "Renders choice options to user"
|
|
454
|
+
derivation: "Resource 'choice' → ChoiceDisplay (presentation UI)"
|
|
455
|
+
|
|
456
|
+
- name: "ChoiceValidator"
|
|
457
|
+
urn: "component:resolve-dilemmas:make-choice.ChoiceValidator.frontend.application"
|
|
458
|
+
purpose: "Validates user selection before submission"
|
|
459
|
+
derivation: "Resource 'choice' → ChoiceValidator (validation logic)"
|
|
460
|
+
|
|
461
|
+
- name: "ChoiceMaker"
|
|
462
|
+
urn: "component:resolve-dilemmas:make-choice.ChoiceMaker.backend.domain"
|
|
463
|
+
purpose: "Applies business rules to make the choice"
|
|
464
|
+
derivation: "Resource 'choice' → ChoiceMaker (core business logic)"
|
|
465
|
+
|
|
466
|
+
- name: "ChoicePersister"
|
|
467
|
+
urn: "component:resolve-dilemmas:make-choice.ChoicePersister.backend.integration"
|
|
468
|
+
purpose: "Persists choice to database"
|
|
469
|
+
derivation: "Resource 'choice' → ChoicePersister (persistence)"
|
|
470
|
+
|
|
471
|
+
# Component limits - similar to WMBT acceptance limits
|
|
472
|
+
component_limits:
|
|
473
|
+
max_per_feature: 8
|
|
474
|
+
rationale: "Beyond 8 components indicates feature is too large and should be split"
|
|
475
|
+
typical_distribution:
|
|
476
|
+
frontend: 2 # presentation + application
|
|
477
|
+
backend: 3 # application + domain + integration
|
|
478
|
+
shared: 3 # cross-cutting concerns
|
|
479
|
+
|
|
480
|
+
layer_distribution:
|
|
481
|
+
frontend: ["presentation", "application"]
|
|
482
|
+
backend: ["application", "domain", "integration"]
|
|
483
|
+
|
|
484
|
+
# Component derivation from feature analysis
|
|
485
|
+
component_derivation:
|
|
486
|
+
from_io_seeds:
|
|
487
|
+
produce_events:
|
|
488
|
+
trigger: "feature.ioSeeds.produce contains event:* or notification:*"
|
|
489
|
+
generates: "Component with event publishing capability"
|
|
490
|
+
layer: "application or integration"
|
|
491
|
+
|
|
492
|
+
consume_events:
|
|
493
|
+
trigger: "feature.ioSeeds.consume contains event:* or notification:*"
|
|
494
|
+
generates: "Component with event handling capability"
|
|
495
|
+
layer: "application or integration"
|
|
496
|
+
|
|
497
|
+
consume_commands:
|
|
498
|
+
trigger: "feature.ioSeeds.consume contains command:*"
|
|
499
|
+
generates: "Component with command processing capability"
|
|
500
|
+
layer: "application"
|
|
501
|
+
|
|
502
|
+
produce_queries:
|
|
503
|
+
trigger: "feature.ioSeeds.produce contains query:*"
|
|
504
|
+
generates: "Component with query handling capability"
|
|
505
|
+
layer: "application or domain"
|
|
506
|
+
|
|
507
|
+
from_wmbt_analysis:
|
|
508
|
+
validation_needs:
|
|
509
|
+
trigger: "WMBTs contain 'validate', 'verify', 'check'"
|
|
510
|
+
generates: "Validation component"
|
|
511
|
+
business_capability: "validator"
|
|
512
|
+
layer: "domain"
|
|
513
|
+
|
|
514
|
+
processing_needs:
|
|
515
|
+
trigger: "WMBTs contain 'process', 'compute', 'calculate'"
|
|
516
|
+
generates: "Processing component"
|
|
517
|
+
business_capability: "processor"
|
|
518
|
+
layer: "application or domain"
|
|
519
|
+
|
|
520
|
+
presentation_needs:
|
|
521
|
+
trigger: "WMBTs contain 'display', 'show', 'render'"
|
|
522
|
+
generates: "Presentation component"
|
|
523
|
+
business_capability: "display"
|
|
524
|
+
layer: "presentation"
|
|
525
|
+
|
|
526
|
+
persistence_needs:
|
|
527
|
+
trigger: "WMBTs contain 'store', 'save', 'persist'"
|
|
528
|
+
generates: "Persistence component"
|
|
529
|
+
business_capability: "persister"
|
|
530
|
+
layer: "integration"
|
|
531
|
+
|
|
532
|
+
coordination_needs:
|
|
533
|
+
trigger: "WMBTs contain 'coordinate', 'orchestrate', 'manage'"
|
|
534
|
+
generates: "Coordination component"
|
|
535
|
+
business_capability: "coordinator"
|
|
536
|
+
layer: "application"
|
|
537
|
+
|
|
538
|
+
# Component naming rules
|
|
539
|
+
component_naming:
|
|
540
|
+
pattern: "{business-capability}-{layer-role}"
|
|
541
|
+
|
|
542
|
+
business_capabilities:
|
|
543
|
+
# Core business functions
|
|
544
|
+
validator: "Validates business rules and constraints"
|
|
545
|
+
processor: "Processes business logic and computations"
|
|
546
|
+
coordinator: "Coordinates multiple operations"
|
|
547
|
+
transformer: "Transforms data between formats"
|
|
548
|
+
aggregator: "Aggregates data from multiple sources"
|
|
549
|
+
|
|
550
|
+
# UI/UX capabilities
|
|
551
|
+
display: "Displays information to users"
|
|
552
|
+
collector: "Collects user input"
|
|
553
|
+
navigator: "Manages navigation flow"
|
|
554
|
+
|
|
555
|
+
# Integration capabilities
|
|
556
|
+
persister: "Persists data to storage"
|
|
557
|
+
fetcher: "Fetches data from external sources"
|
|
558
|
+
publisher: "Publishes events/notifications"
|
|
559
|
+
subscriber: "Subscribes to events/notifications"
|
|
560
|
+
|
|
561
|
+
examples:
|
|
562
|
+
- "option-validator" # Validates user options
|
|
563
|
+
- "decision-processor" # Processes decisions
|
|
564
|
+
- "dilemma-display" # Displays dilemma UI
|
|
565
|
+
- "choice-persister" # Persists choice data
|
|
566
|
+
- "result-publisher" # Publishes results
|
|
567
|
+
|
|
568
|
+
# Component structure generation rules
|
|
569
|
+
component_structure:
|
|
570
|
+
urn:
|
|
571
|
+
pattern: "component:{wagon}.{feature}.{business_capability}.{side}.{layer}"
|
|
572
|
+
example: "component:resolve-dilemmas:choose-option.option-validator.backend.domain"
|
|
573
|
+
note: "Pattern updated to use {side} instead of {tier} for clarity"
|
|
574
|
+
|
|
575
|
+
parent_feature:
|
|
576
|
+
source: "feature URN from input"
|
|
577
|
+
required: true
|
|
578
|
+
|
|
579
|
+
description:
|
|
580
|
+
template: "Handles {business_capability} for {feature} using {layer} patterns"
|
|
581
|
+
example: "Handles validation for choose-option using domain patterns"
|
|
582
|
+
|
|
583
|
+
events:
|
|
584
|
+
consumes:
|
|
585
|
+
source: "feature.ioSeeds.consume filtered by component role"
|
|
586
|
+
maximum: 3
|
|
587
|
+
example: ["dilemma:presented", "user:authenticated"]
|
|
588
|
+
|
|
589
|
+
produces:
|
|
590
|
+
source: "feature.ioSeeds.produce filtered by component capability"
|
|
591
|
+
maximum: 3
|
|
592
|
+
example: ["decision:made", "validation:completed"]
|
|
593
|
+
|
|
594
|
+
dependencies:
|
|
595
|
+
source: "Other components in same feature + external dependencies"
|
|
596
|
+
example: ["component:same:feature.other", "wagon:external#io"]
|
|
597
|
+
|
|
598
|
+
# Layer-specific patterns
|
|
599
|
+
layer_patterns:
|
|
600
|
+
presentation:
|
|
601
|
+
typical_methods: ["render", "handleInput", "updateDisplay"]
|
|
602
|
+
consumes: ["user interactions", "display updates"]
|
|
603
|
+
produces: ["ui events", "user actions"]
|
|
604
|
+
|
|
605
|
+
application:
|
|
606
|
+
typical_methods: ["execute", "coordinate", "validate"]
|
|
607
|
+
consumes: ["commands", "queries"]
|
|
608
|
+
produces: ["events", "responses"]
|
|
609
|
+
|
|
610
|
+
domain:
|
|
611
|
+
typical_methods: ["process", "calculate", "applyRules"]
|
|
612
|
+
consumes: ["domain events"]
|
|
613
|
+
produces: ["domain events", "state changes"]
|
|
614
|
+
|
|
615
|
+
integration:
|
|
616
|
+
typical_methods: ["fetch", "save", "publish"]
|
|
617
|
+
consumes: ["external events"]
|
|
618
|
+
produces: ["external calls", "persistence operations"]
|
|
619
|
+
|
|
620
|
+
# Validation rules
|
|
621
|
+
validation_rules:
|
|
622
|
+
component_count:
|
|
623
|
+
rule: "Feature must have ≤ 8 components"
|
|
624
|
+
action: "Split feature if more components needed"
|
|
625
|
+
|
|
626
|
+
business_focus:
|
|
627
|
+
rule: "Each component must have single business capability"
|
|
628
|
+
check: "Component name reflects its primary business purpose"
|
|
629
|
+
|
|
630
|
+
layer_consistency:
|
|
631
|
+
rule: "Component belongs to exactly one layer"
|
|
632
|
+
check: "URN contains valid layer: presentation|application|domain|integration"
|
|
633
|
+
|
|
634
|
+
io_alignment:
|
|
635
|
+
rule: "Component events must subset of feature ioSeeds"
|
|
636
|
+
check: "All consumed/produced events traceable to feature ioSeeds"
|
|
637
|
+
|
|
638
|
+
method_limit:
|
|
639
|
+
rule: "Component has ≤ 5 methods"
|
|
640
|
+
action: "Split component if more methods needed"
|
|
641
|
+
|
|
642
|
+
# Component generation strategy
|
|
643
|
+
generation_strategy:
|
|
644
|
+
step_1_analyze: "Analyze feature ioSeeds and WMBTs"
|
|
645
|
+
step_2_identify: "Identify needed business capabilities"
|
|
646
|
+
step_3_assign: "Assign capabilities to appropriate layers"
|
|
647
|
+
step_4_generate: "Generate up to 8 components with complete structure"
|
|
648
|
+
step_5_validate: "Ensure all feature needs covered by components"
|
|
649
|
+
|
|
650
|
+
# Examples of feature → component mapping
|
|
651
|
+
mapping_examples:
|
|
652
|
+
binary_choice_feature:
|
|
653
|
+
input:
|
|
654
|
+
ioSeeds:
|
|
655
|
+
consume: ["dilemma:presented"]
|
|
656
|
+
produce: ["decision:made"]
|
|
657
|
+
wmbts: ["validate options", "process choice", "display result"]
|
|
658
|
+
|
|
659
|
+
output_components:
|
|
660
|
+
- business_capability: "option-validator"
|
|
661
|
+
layer: "domain"
|
|
662
|
+
reason: "WMBT mentions validation"
|
|
663
|
+
|
|
664
|
+
- business_capability: "choice-processor"
|
|
665
|
+
layer: "application"
|
|
666
|
+
reason: "WMBT mentions processing"
|
|
667
|
+
|
|
668
|
+
- business_capability: "result-display"
|
|
669
|
+
layer: "presentation"
|
|
670
|
+
reason: "WMBT mentions display"
|