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,178 @@
|
|
|
1
|
+
# URN naming pattern
|
|
2
|
+
urn_naming:
|
|
3
|
+
pattern: "component:{wagon}:{feature}[.{objectCamelCase}][.{side}][.{layer}][@vN]"
|
|
4
|
+
description: "Stable component URN: hierarchy via colons (kind:wagon:feature), optional facets via dots."
|
|
5
|
+
utility: "utils.graph.URNBuilder.component(wagon_id, feature_id, component_name?, side?, layer?, version?)"
|
|
6
|
+
|
|
7
|
+
parts:
|
|
8
|
+
wagon: "Parent wagon identifier (kebab-case)"
|
|
9
|
+
feature: "Parent feature identifier (kebab-case)"
|
|
10
|
+
objectCamelCase: "Component name in PascalCase or camelCase"
|
|
11
|
+
side: "Component deployment side (frontend|backend)"
|
|
12
|
+
layer: "Architectural layer (presentation|application|domain|integration)"
|
|
13
|
+
version: "@vN suffix for explicit versioning (optional), e.g., @v2"
|
|
14
|
+
|
|
15
|
+
rules:
|
|
16
|
+
hierarchy_separator: ":"
|
|
17
|
+
facet_separator: "."
|
|
18
|
+
casing:
|
|
19
|
+
wagon_feature: "^[a-z][a-z0-9-]*$"
|
|
20
|
+
facets:
|
|
21
|
+
- "^[a-z][a-z0-9-]*$" # kebab/lower facet allowed
|
|
22
|
+
- "^[A-Z][a-zA-Z0-9]*$" # CamelCase facet allowed
|
|
23
|
+
no_file_extensions: "Do not include .py/.dart/etc. Use a 'lang-*' facet if needed."
|
|
24
|
+
case_policy: "IDs are case-sensitive; store exactly as written."
|
|
25
|
+
|
|
26
|
+
examples:
|
|
27
|
+
- urn: "component:resolve-dilemmas:choose-option.OptionValidator.backend.domain"
|
|
28
|
+
wagon: "resolve-dilemmas"
|
|
29
|
+
feature: "choose-option"
|
|
30
|
+
component: "OptionValidator"
|
|
31
|
+
side: "backend"
|
|
32
|
+
layer: "domain"
|
|
33
|
+
|
|
34
|
+
- urn: "component:manage-users:authenticate-user.LoginForm.frontend.presentation"
|
|
35
|
+
wagon: "manage-users"
|
|
36
|
+
feature: "authenticate-user"
|
|
37
|
+
component: "LoginForm"
|
|
38
|
+
side: "frontend"
|
|
39
|
+
layer: "presentation"
|
|
40
|
+
|
|
41
|
+
note: "Side and layer values are defined by component_type_catalog structure below"
|
|
42
|
+
|
|
43
|
+
# Artifact derivation for component naming
|
|
44
|
+
artifact_derivation:
|
|
45
|
+
description: "How to derive component names from artifact resources"
|
|
46
|
+
overview: |
|
|
47
|
+
Component names come from artifact resources (the part after colon).
|
|
48
|
+
Transform resource to PascalCase and add capability suffix based on artifact type.
|
|
49
|
+
Components describe CAPABILITY to handle artifacts.
|
|
50
|
+
|
|
51
|
+
rules:
|
|
52
|
+
pascalcase_conversion:
|
|
53
|
+
rule: "Convert artifact resource to PascalCase"
|
|
54
|
+
examples:
|
|
55
|
+
- from: "choice"
|
|
56
|
+
to: "Choice"
|
|
57
|
+
- from: "player-wallet"
|
|
58
|
+
to: "PlayerWallet"
|
|
59
|
+
- from: "domain-impacts"
|
|
60
|
+
to: "DomainImpacts"
|
|
61
|
+
- from: "remaining"
|
|
62
|
+
to: "Remaining"
|
|
63
|
+
|
|
64
|
+
capability_suffix:
|
|
65
|
+
rule: "Add capability suffix based on artifact type and component responsibility"
|
|
66
|
+
by_artifact_type:
|
|
67
|
+
events:
|
|
68
|
+
description: "Past tense resources (started, closed, credited)"
|
|
69
|
+
suffixes: ["Publisher", "Emitter", "Broadcaster"]
|
|
70
|
+
examples:
|
|
71
|
+
- artifact: "match:started"
|
|
72
|
+
resource: "started"
|
|
73
|
+
component: "MatchStartedPublisher"
|
|
74
|
+
urn: "component:resolve-dilemmas:make-choice.MatchStartedPublisher.backend.integration"
|
|
75
|
+
|
|
76
|
+
- artifact: "wallet:credited"
|
|
77
|
+
resource: "credited"
|
|
78
|
+
component: "WalletCreditedEmitter"
|
|
79
|
+
urn: "component:manage-wallets:credit-wallet.WalletCreditedEmitter.backend.integration"
|
|
80
|
+
|
|
81
|
+
states:
|
|
82
|
+
description: "Adjective resources (remaining, active, current)"
|
|
83
|
+
suffixes: ["Tracker", "Monitor", "Manager"]
|
|
84
|
+
examples:
|
|
85
|
+
- artifact: "mechanic:timebank.remaining"
|
|
86
|
+
resource: "remaining"
|
|
87
|
+
component: "TimebankTracker"
|
|
88
|
+
urn: "component:burn-timebank:track-timebank.TimebankTracker.backend.domain"
|
|
89
|
+
|
|
90
|
+
- artifact: "session:active"
|
|
91
|
+
resource: "active"
|
|
92
|
+
component: "SessionManager"
|
|
93
|
+
urn: "component:init-session:maintain-session.SessionManager.backend.application"
|
|
94
|
+
|
|
95
|
+
data:
|
|
96
|
+
description: "Noun resources (choice, identity, profile)"
|
|
97
|
+
suffixes: ["Provider", "Handler", "Processor", "Maker"]
|
|
98
|
+
examples:
|
|
99
|
+
- artifact: "mechanic:decision.choice"
|
|
100
|
+
resource: "choice"
|
|
101
|
+
component: "ChoiceMaker"
|
|
102
|
+
urn: "component:resolve-dilemmas:make-choice.ChoiceMaker.backend.domain"
|
|
103
|
+
|
|
104
|
+
- artifact: "player:identity"
|
|
105
|
+
resource: "identity"
|
|
106
|
+
component: "IdentityProvider"
|
|
107
|
+
urn: "component:contextualize-identity:identify-player.IdentityProvider.backend.application"
|
|
108
|
+
|
|
109
|
+
configs:
|
|
110
|
+
description: "Configuration resources (config, settings, agreement)"
|
|
111
|
+
suffixes: ["Configurator", "Builder", "Initializer"]
|
|
112
|
+
examples:
|
|
113
|
+
- artifact: "match:config"
|
|
114
|
+
resource: "config"
|
|
115
|
+
component: "MatchConfigurator"
|
|
116
|
+
urn: "component:setup-match:configure-match.MatchConfigurator.backend.application"
|
|
117
|
+
|
|
118
|
+
- artifact: "league:config"
|
|
119
|
+
resource: "config"
|
|
120
|
+
component: "LeagueBuilder"
|
|
121
|
+
urn: "component:define-league:configure-league.LeagueBuilder.backend.application"
|
|
122
|
+
|
|
123
|
+
layer_assignment:
|
|
124
|
+
description: "Assign components to layers based on artifact type and responsibility"
|
|
125
|
+
|
|
126
|
+
events:
|
|
127
|
+
typical_layers: ["integration", "application"]
|
|
128
|
+
rationale: "Event publishers at boundaries (external integration or internal application)"
|
|
129
|
+
examples:
|
|
130
|
+
- "MatchStartedPublisher → backend.integration (publishes to external systems)"
|
|
131
|
+
- "StateCommittedEmitter → backend.application (emits internal events)"
|
|
132
|
+
|
|
133
|
+
states:
|
|
134
|
+
typical_layers: ["domain", "application"]
|
|
135
|
+
rationale: "State trackers manage business state (domain) or coordinate (application)"
|
|
136
|
+
examples:
|
|
137
|
+
- "TimebankTracker → backend.domain (tracks core business state)"
|
|
138
|
+
- "SessionManager → backend.application (coordinates session lifecycle)"
|
|
139
|
+
|
|
140
|
+
data:
|
|
141
|
+
typical_layers: ["domain", "application", "integration"]
|
|
142
|
+
rationale: "Data handlers span layers based on responsibility"
|
|
143
|
+
examples:
|
|
144
|
+
- "ChoiceMaker → backend.domain (business logic for making choice)"
|
|
145
|
+
- "ChoiceHandler → backend.application (coordinates choice workflow)"
|
|
146
|
+
- "ChoicePersister → backend.integration (persists to database)"
|
|
147
|
+
|
|
148
|
+
configs:
|
|
149
|
+
typical_layers: ["application", "integration"]
|
|
150
|
+
rationale: "Configuration components coordinate setup or load settings"
|
|
151
|
+
examples:
|
|
152
|
+
- "MatchConfigurator → backend.application (coordinates match setup)"
|
|
153
|
+
- "ConfigLoader → backend.integration (loads from external config store)"
|
|
154
|
+
|
|
155
|
+
complete_example:
|
|
156
|
+
artifact: "mechanic:decision.choice"
|
|
157
|
+
wagon: "resolve-dilemmas"
|
|
158
|
+
feature: "make-choice"
|
|
159
|
+
components:
|
|
160
|
+
- name: "ChoiceDisplay"
|
|
161
|
+
urn: "component:resolve-dilemmas:make-choice.ChoiceDisplay.frontend.presentation"
|
|
162
|
+
purpose: "Renders choice options to user"
|
|
163
|
+
derivation: "Resource 'choice' → ChoiceDisplay (presentation UI)"
|
|
164
|
+
|
|
165
|
+
- name: "ChoiceValidator"
|
|
166
|
+
urn: "component:resolve-dilemmas:make-choice.ChoiceValidator.frontend.application"
|
|
167
|
+
purpose: "Validates user selection before submission"
|
|
168
|
+
derivation: "Resource 'choice' → ChoiceValidator (validation logic)"
|
|
169
|
+
|
|
170
|
+
- name: "ChoiceMaker"
|
|
171
|
+
urn: "component:resolve-dilemmas:make-choice.ChoiceMaker.backend.domain"
|
|
172
|
+
purpose: "Applies business rules to make the choice"
|
|
173
|
+
derivation: "Resource 'choice' → ChoiceMaker (core business logic)"
|
|
174
|
+
|
|
175
|
+
- name: "ChoicePersister"
|
|
176
|
+
urn: "component:resolve-dilemmas:make-choice.ChoicePersister.backend.integration"
|
|
177
|
+
purpose: "Persists choice to database"
|
|
178
|
+
derivation: "Resource 'choice' → ChoicePersister (persistence)"
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
schema_version: "1.0.1"
|
|
2
|
+
convention_id: "coder.design_system"
|
|
3
|
+
name: "Design System Convention"
|
|
4
|
+
description: "Hierarchy rules and validation standards for design system architecture within presentation layer."
|
|
5
|
+
|
|
6
|
+
design_system:
|
|
7
|
+
goal: "Enforce reusable UI patterns via tokens → primitives → components → templates hierarchy"
|
|
8
|
+
|
|
9
|
+
location:
|
|
10
|
+
path: "lib/design_system/"
|
|
11
|
+
note: "Design system is a shared wagon at same level as feature wagons"
|
|
12
|
+
structure:
|
|
13
|
+
- "tokens/" # Pure values
|
|
14
|
+
- "primitives/" # Basic components
|
|
15
|
+
- "components/" # Composed from primitives
|
|
16
|
+
- "templates/" # Composed from components
|
|
17
|
+
|
|
18
|
+
principles:
|
|
19
|
+
- id: DS-01
|
|
20
|
+
text: "Tokens are pure values (no logic, no widgets)"
|
|
21
|
+
- id: DS-02
|
|
22
|
+
text: "Primitives are simplest components consuming tokens"
|
|
23
|
+
- id: DS-03
|
|
24
|
+
text: "Components compose primitives and tokens only"
|
|
25
|
+
- id: DS-04
|
|
26
|
+
text: "Templates compose components, primitives, and tokens"
|
|
27
|
+
- id: DS-05
|
|
28
|
+
text: "Dependency flow: tokens ← primitives ← components ← templates"
|
|
29
|
+
- id: DS-06
|
|
30
|
+
text: "Wagons import from design_system, never reverse"
|
|
31
|
+
- id: DS-07
|
|
32
|
+
text: "Extract to design_system on 3rd occurrence (DRY threshold)"
|
|
33
|
+
|
|
34
|
+
layers:
|
|
35
|
+
tokens:
|
|
36
|
+
description: "Pure design values (spacing, radii, motion)"
|
|
37
|
+
path: "design_system/tokens/"
|
|
38
|
+
file_suffix:
|
|
39
|
+
dart: "*_tokens.dart"
|
|
40
|
+
can_import:
|
|
41
|
+
- "dart:core"
|
|
42
|
+
- "package:flutter/material.dart (for Duration, EdgeInsets)"
|
|
43
|
+
cannot_import:
|
|
44
|
+
- "primitives/"
|
|
45
|
+
- "components/"
|
|
46
|
+
- "templates/"
|
|
47
|
+
- "wagons/*"
|
|
48
|
+
examples:
|
|
49
|
+
- "spacing_tokens.dart: AppSpacing.m = 16.0"
|
|
50
|
+
- "radii_tokens.dart: AppRadii.m = 8.0"
|
|
51
|
+
- "motion_tokens.dart: AppMotion.base = Duration(milliseconds: 250)"
|
|
52
|
+
validation:
|
|
53
|
+
- type: no_widgets
|
|
54
|
+
message: "Tokens must not contain widget definitions"
|
|
55
|
+
- type: no_logic
|
|
56
|
+
message: "Tokens are pure values, no business logic"
|
|
57
|
+
|
|
58
|
+
primitives:
|
|
59
|
+
description: "Simplest reusable components (AppBox, AppText, AppIcon)"
|
|
60
|
+
path: "design_system/primitives/"
|
|
61
|
+
file_suffix:
|
|
62
|
+
dart: "*_primitive.dart"
|
|
63
|
+
naming_convention: "App{Primitive} (e.g., AppBox, AppText)"
|
|
64
|
+
can_import:
|
|
65
|
+
- "../tokens/"
|
|
66
|
+
- "dart:core"
|
|
67
|
+
- "package:flutter/widgets.dart"
|
|
68
|
+
- "package:flutter/material.dart"
|
|
69
|
+
cannot_import:
|
|
70
|
+
- "../components/"
|
|
71
|
+
- "../templates/"
|
|
72
|
+
- "wagons/*"
|
|
73
|
+
examples:
|
|
74
|
+
- "app_box_primitive.dart: Container abstraction with token-based styling"
|
|
75
|
+
- "app_text_primitive.dart: Text abstraction with theme typography"
|
|
76
|
+
- "app_icon_primitive.dart: Icon abstraction with token-based sizing"
|
|
77
|
+
validation:
|
|
78
|
+
- type: import_scan
|
|
79
|
+
forbid:
|
|
80
|
+
- "primitives → components"
|
|
81
|
+
- "primitives → templates"
|
|
82
|
+
- type: must_use_tokens
|
|
83
|
+
message: "Primitives should reference tokens for spacing/sizing/radii"
|
|
84
|
+
|
|
85
|
+
components:
|
|
86
|
+
description: "Composed UI elements (AppButton, AppTextField, AppCard)"
|
|
87
|
+
path: "design_system/components/"
|
|
88
|
+
file_suffix:
|
|
89
|
+
dart: "*_component.dart"
|
|
90
|
+
naming_convention: "App{Component} (e.g., AppButton, AppTextField)"
|
|
91
|
+
can_import:
|
|
92
|
+
- "../tokens/"
|
|
93
|
+
- "../primitives/"
|
|
94
|
+
- "dart:core"
|
|
95
|
+
- "package:flutter/widgets.dart"
|
|
96
|
+
- "package:flutter/material.dart"
|
|
97
|
+
cannot_import:
|
|
98
|
+
- "../templates/"
|
|
99
|
+
- "wagons/*"
|
|
100
|
+
examples:
|
|
101
|
+
- "app_button_component.dart: Button using AppBox + AppText"
|
|
102
|
+
- "app_text_field_component.dart: Input using AppBox + theme"
|
|
103
|
+
- "app_card_component.dart: Card using AppBox + elevation"
|
|
104
|
+
validation:
|
|
105
|
+
- type: import_scan
|
|
106
|
+
forbid:
|
|
107
|
+
- "components → templates"
|
|
108
|
+
- type: composition_check
|
|
109
|
+
recommend: "Use primitives over raw Container/Text widgets"
|
|
110
|
+
|
|
111
|
+
templates:
|
|
112
|
+
description: "Multi-component UI patterns (EmptyState, ListWithFilter)"
|
|
113
|
+
path: "design_system/templates/"
|
|
114
|
+
file_suffix:
|
|
115
|
+
dart: "*_template.dart"
|
|
116
|
+
naming_convention: "Descriptive name (e.g., EmptyState, ListWithFilter)"
|
|
117
|
+
can_import:
|
|
118
|
+
- "../tokens/"
|
|
119
|
+
- "../primitives/"
|
|
120
|
+
- "../components/"
|
|
121
|
+
- "dart:core"
|
|
122
|
+
- "package:flutter/widgets.dart"
|
|
123
|
+
- "package:flutter/material.dart"
|
|
124
|
+
cannot_import:
|
|
125
|
+
- "wagons/*"
|
|
126
|
+
examples:
|
|
127
|
+
- "empty_state_template.dart: Icon + Title + Description + Button"
|
|
128
|
+
- "list_with_filter_template.dart: Search + List + EmptyState"
|
|
129
|
+
validation:
|
|
130
|
+
- type: composition_check
|
|
131
|
+
recommend: "Templates should primarily use components, not raw primitives"
|
|
132
|
+
|
|
133
|
+
dependency_rules:
|
|
134
|
+
allowed_edges:
|
|
135
|
+
- from: primitives
|
|
136
|
+
to: [tokens]
|
|
137
|
+
- from: components
|
|
138
|
+
to: [tokens, primitives]
|
|
139
|
+
- from: templates
|
|
140
|
+
to: [tokens, primitives, components]
|
|
141
|
+
- from: wagons
|
|
142
|
+
to: [design_system/tokens, design_system/primitives, design_system/components, design_system/templates]
|
|
143
|
+
|
|
144
|
+
forbidden_edges:
|
|
145
|
+
- from: tokens
|
|
146
|
+
to: [primitives, components, templates]
|
|
147
|
+
message: "Tokens cannot import other design system layers"
|
|
148
|
+
- from: primitives
|
|
149
|
+
to: [components, templates]
|
|
150
|
+
message: "Primitives can only import tokens"
|
|
151
|
+
- from: components
|
|
152
|
+
to: [templates]
|
|
153
|
+
message: "Components cannot import templates"
|
|
154
|
+
- from: design_system
|
|
155
|
+
to: [wagons]
|
|
156
|
+
message: "Design system cannot import from feature wagons"
|
|
157
|
+
|
|
158
|
+
cross_wagon:
|
|
159
|
+
forbidden: true
|
|
160
|
+
message: "Wagons cannot import from other wagons (except via design_system or shared packages)"
|
|
161
|
+
|
|
162
|
+
extraction_rules:
|
|
163
|
+
dry_threshold:
|
|
164
|
+
occurrences: 3
|
|
165
|
+
rule: "Extract pattern to design_system on 3rd occurrence"
|
|
166
|
+
rationale: "Avoid premature abstraction; wait for proven reuse need"
|
|
167
|
+
|
|
168
|
+
token_extraction:
|
|
169
|
+
triggers:
|
|
170
|
+
- "Hardcoded spacing: EdgeInsets.all(16.0)"
|
|
171
|
+
- "Hardcoded radius: BorderRadius.circular(8.0)"
|
|
172
|
+
- "Hardcoded duration: Duration(milliseconds: 250)"
|
|
173
|
+
- "Hardcoded color: Color(0xFF...)"
|
|
174
|
+
actions:
|
|
175
|
+
- "Extract to appropriate token file"
|
|
176
|
+
- "Reuse if token value already exists"
|
|
177
|
+
- "Colors: prefer theme over tokens"
|
|
178
|
+
|
|
179
|
+
primitive_extraction:
|
|
180
|
+
triggers:
|
|
181
|
+
- "Repeated Container patterns (3+ similar usages)"
|
|
182
|
+
- "Repeated Text patterns with consistent styling"
|
|
183
|
+
- "Repeated Icon patterns"
|
|
184
|
+
actions:
|
|
185
|
+
- "Create primitive if not exists"
|
|
186
|
+
- "Primitive must only import tokens"
|
|
187
|
+
- "Name: App{Widget} (AppBox, AppText, AppIcon)"
|
|
188
|
+
|
|
189
|
+
component_extraction:
|
|
190
|
+
triggers:
|
|
191
|
+
- "Repeated composed widgets (button-like patterns)"
|
|
192
|
+
- "Similar input field patterns"
|
|
193
|
+
- "Card/container patterns with interaction"
|
|
194
|
+
actions:
|
|
195
|
+
- "Create component if not exists"
|
|
196
|
+
- "Component must use primitives (not raw widgets)"
|
|
197
|
+
- "Name: App{Component} (AppButton, AppTextField)"
|
|
198
|
+
|
|
199
|
+
template_extraction:
|
|
200
|
+
triggers:
|
|
201
|
+
- "Repeated multi-component patterns"
|
|
202
|
+
- "Common layouts (empty state, list+filter)"
|
|
203
|
+
- "Used across 2+ features"
|
|
204
|
+
actions:
|
|
205
|
+
- "Create template if not exists"
|
|
206
|
+
- "Template must primarily use components"
|
|
207
|
+
- "Descriptive name reflecting UI pattern"
|
|
208
|
+
|
|
209
|
+
validation_checks:
|
|
210
|
+
- id: VC-DS-01
|
|
211
|
+
name: "No hardcoded spacing in wagons"
|
|
212
|
+
check: "grep -r 'EdgeInsets\\.[a-z]*([0-9]' lib/*/features/"
|
|
213
|
+
must_not_match: true
|
|
214
|
+
fix: "Use AppSpacing tokens"
|
|
215
|
+
|
|
216
|
+
- id: VC-DS-02
|
|
217
|
+
name: "No hardcoded colors in wagons"
|
|
218
|
+
check: "grep -r 'Color(0x' lib/*/features/"
|
|
219
|
+
must_not_match: true
|
|
220
|
+
fix: "Use Theme.of(context).colorScheme"
|
|
221
|
+
|
|
222
|
+
- id: VC-DS-03
|
|
223
|
+
name: "Primitives don't import components"
|
|
224
|
+
check_imports:
|
|
225
|
+
path: "lib/design_system/primitives/"
|
|
226
|
+
forbid: "../components/"
|
|
227
|
+
violation: "DS-05: Primitives can only import tokens"
|
|
228
|
+
|
|
229
|
+
- id: VC-DS-04
|
|
230
|
+
name: "Components don't import templates"
|
|
231
|
+
check_imports:
|
|
232
|
+
path: "lib/design_system/components/"
|
|
233
|
+
forbid: "../templates/"
|
|
234
|
+
violation: "DS-05: Components cannot import templates"
|
|
235
|
+
|
|
236
|
+
- id: VC-DS-05
|
|
237
|
+
name: "Design system doesn't import wagons"
|
|
238
|
+
check_imports:
|
|
239
|
+
path: "lib/design_system/"
|
|
240
|
+
forbid_pattern: "package:app/((?!design_system)[^/]+)/"
|
|
241
|
+
violation: "DS-06: design_system cannot import from wagons"
|
|
242
|
+
|
|
243
|
+
- id: VC-DS-06
|
|
244
|
+
name: "No cross-wagon imports"
|
|
245
|
+
check_imports:
|
|
246
|
+
path: "lib/*/features/"
|
|
247
|
+
forbid_pattern: "package:app/((?!design_system)[^/]+)/features/"
|
|
248
|
+
violation: "Wagons cannot import from other wagons"
|
|
249
|
+
|
|
250
|
+
metrics:
|
|
251
|
+
- id: METRIC-DS-01
|
|
252
|
+
name: "Design system coverage"
|
|
253
|
+
formula: "wagons_using_ds / total_wagons"
|
|
254
|
+
target: ">= 80%"
|
|
255
|
+
description: "Percentage of wagons using design system components"
|
|
256
|
+
|
|
257
|
+
- id: METRIC-DS-02
|
|
258
|
+
name: "Component reuse rate"
|
|
259
|
+
formula: "avg(component_usage_count)"
|
|
260
|
+
target: ">= 3"
|
|
261
|
+
description: "Average number of wagons using each component"
|
|
262
|
+
|
|
263
|
+
- id: METRIC-DS-03
|
|
264
|
+
name: "Hardcoded value density"
|
|
265
|
+
formula: "hardcoded_tokens / total_ui_files"
|
|
266
|
+
target: "< 5%"
|
|
267
|
+
description: "Percentage of UI files with hardcoded values"
|
|
268
|
+
|
|
269
|
+
- id: METRIC-DS-04
|
|
270
|
+
name: "Hierarchy compliance"
|
|
271
|
+
formula: "valid_imports / total_imports"
|
|
272
|
+
target: "100%"
|
|
273
|
+
description: "All imports follow hierarchy rules"
|
|
274
|
+
|
|
275
|
+
ci_enforcement:
|
|
276
|
+
on: "pull_request"
|
|
277
|
+
checks:
|
|
278
|
+
- name: "validate_design_system_hierarchy"
|
|
279
|
+
command: "python .claude/utils/coder/design.py --validate-hierarchy"
|
|
280
|
+
on_failure: "block"
|
|
281
|
+
|
|
282
|
+
- name: "scan_hardcoded_tokens"
|
|
283
|
+
command: "python .claude/utils/coder/design.py --scan-tokens lib/*/features/"
|
|
284
|
+
on_failure: "warn"
|
|
285
|
+
|
|
286
|
+
- name: "check_import_rules"
|
|
287
|
+
command: "python .claude/utils/coder/design.py --check-imports"
|
|
288
|
+
on_failure: "block"
|
|
289
|
+
|
|
290
|
+
- name: "design_system_metrics"
|
|
291
|
+
command: "python .claude/utils/coder/design.py --metrics"
|
|
292
|
+
on_failure: "report_only"
|
|
293
|
+
|
|
294
|
+
anti_patterns:
|
|
295
|
+
- id: AP-DS-01
|
|
296
|
+
text: "Premature abstraction"
|
|
297
|
+
avoid: "Creating design system components before 3rd usage"
|
|
298
|
+
fix: "Wait for proven reuse need (DRY threshold: 3)"
|
|
299
|
+
|
|
300
|
+
- id: AP-DS-02
|
|
301
|
+
text: "Leaky abstraction"
|
|
302
|
+
avoid: "Design system components importing from wagons"
|
|
303
|
+
fix: "Design system must be wagon-agnostic"
|
|
304
|
+
|
|
305
|
+
- id: AP-DS-03
|
|
306
|
+
text: "Hierarchy bypass"
|
|
307
|
+
avoid: "Components using raw Container instead of AppBox"
|
|
308
|
+
fix: "Always use lower-level abstractions"
|
|
309
|
+
|
|
310
|
+
- id: AP-DS-04
|
|
311
|
+
text: "Token duplication"
|
|
312
|
+
avoid: "Creating new token when similar value exists"
|
|
313
|
+
fix: "Reuse existing tokens (e.g., AppSpacing.m = 16, don't create new 16px token)"
|
|
314
|
+
|
|
315
|
+
- id: AP-DS-05
|
|
316
|
+
text: "God component"
|
|
317
|
+
avoid: "Single component with too many variants/options"
|
|
318
|
+
fix: "Split into multiple focused components"
|
|
319
|
+
|
|
320
|
+
handoff_criteria:
|
|
321
|
+
description: "Ready for wagon refactoring when design system meets criteria"
|
|
322
|
+
checklist:
|
|
323
|
+
- "Token files created (spacing, radii, motion)"
|
|
324
|
+
- "Core primitives exist (AppBox, AppText, AppIcon)"
|
|
325
|
+
- "No hardcoded values in existing design system components"
|
|
326
|
+
- "Hierarchy validation passing"
|
|
327
|
+
- "Zero design_system → wagon imports"
|