create-shhs 1.0.0 → 1.1.0

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.
@@ -0,0 +1,410 @@
1
+ # Fitness Functions — Usage Guide
2
+
3
+ **Purpose:** Automate enforcement of architectural constraints to prevent decay.
4
+
5
+ **Owner:** Fitness Enforcer Agent
6
+
7
+ ---
8
+
9
+ ## What Are Fitness Functions?
10
+
11
+ Architectural fitness functions are automated tests of structural properties.
12
+
13
+ Unlike traditional tests (which verify behavior), fitness functions verify **architecture compliance**.
14
+
15
+ **Examples:**
16
+ - "Presentation layer cannot import database layer"
17
+ - "No module may have >10 dependencies"
18
+ - "Domain boundaries must not leak"
19
+
20
+ ---
21
+
22
+ ## Directory Structure
23
+
24
+ ```
25
+ .ai/architecture/governance/fitness/
26
+ ├── README.md # This file
27
+ ├── config.json # Enforcement mode and settings
28
+ ├── rules.json # Fitness function definitions
29
+ └── exemptions.json # Temporary overrides
30
+ ```
31
+
32
+ ---
33
+
34
+ ## Configuration
35
+
36
+ ### `config.json`
37
+
38
+ ```json
39
+ {
40
+ "mode": "PREVENT",
41
+ "exemptions_enabled": true,
42
+ "metrics_retention_days": 365,
43
+ "report_output": ".ai/reports/fitness-violations.json",
44
+ "trend_analysis_enabled": true
45
+ }
46
+ ```
47
+
48
+ **Mode:**
49
+ - `DETECT`: Log violations, allow merge (for legacy codebases)
50
+ - `PREVENT`: Block merge on BLOCK-severity violations (for strict governance)
51
+
52
+ ---
53
+
54
+ ## Defining Fitness Rules
55
+
56
+ ### `rules.json`
57
+
58
+ Each rule has:
59
+
60
+ | Field | Description |
61
+ |-------|-------------|
62
+ | `id` | Unique identifier (kebab-case) |
63
+ | `description` | Human-readable explanation |
64
+ | `condition` | What to measure |
65
+ | `threshold` | Acceptable limit |
66
+ | `severity` | `WARN` or `BLOCK` |
67
+ | `scope` | Glob pattern for files |
68
+
69
+ ### Condition Types
70
+
71
+ #### 1. Import Pattern
72
+
73
+ Detects forbidden imports.
74
+
75
+ ```json
76
+ {
77
+ "type": "import_pattern",
78
+ "pattern": "src/presentation/.*\\.ts imports (prisma|database).*"
79
+ }
80
+ ```
81
+
82
+ #### 2. Dependency Count
83
+
84
+ Counts direct dependencies per file.
85
+
86
+ ```json
87
+ {
88
+ "type": "dependency_count",
89
+ "target": "file"
90
+ }
91
+ ```
92
+
93
+ #### 3. Centrality
94
+
95
+ Measures how many modules import a given module.
96
+
97
+ ```json
98
+ {
99
+ "type": "centrality",
100
+ "metric": "incoming_dependencies_percentage"
101
+ }
102
+ ```
103
+
104
+ #### 4. Complexity
105
+
106
+ Cyclomatic complexity of functions.
107
+
108
+ ```json
109
+ {
110
+ "type": "complexity",
111
+ "metric": "cyclomatic"
112
+ }
113
+ ```
114
+
115
+ ---
116
+
117
+ ## Example Rules
118
+
119
+ ### Rule: No Cross-Domain Database Access
120
+
121
+ ```json
122
+ {
123
+ "id": "cross-domain-db-access",
124
+ "description": "Domain modules must not directly access other domain databases",
125
+ "condition": {
126
+ "type": "import_pattern",
127
+ "pattern": "src/domain-a/.*\\.ts imports @prisma/client.*domain_b.*"
128
+ },
129
+ "threshold": 0,
130
+ "severity": "BLOCK",
131
+ "scope": "src/domain-*/**/*.ts"
132
+ }
133
+ ```
134
+
135
+ ### Rule: Max Module Dependencies
136
+
137
+ ```json
138
+ {
139
+ "id": "max-module-dependencies",
140
+ "description": "No module may have more than 10 direct dependencies",
141
+ "condition": {
142
+ "type": "dependency_count",
143
+ "target": "file"
144
+ },
145
+ "threshold": 10,
146
+ "severity": "WARN",
147
+ "scope": "src/**/*.ts"
148
+ }
149
+ ```
150
+
151
+ ---
152
+
153
+ ## Exemptions
154
+
155
+ Temporary overrides for legacy code or justified exceptions.
156
+
157
+ ### `exemptions.json`
158
+
159
+ ```json
160
+ {
161
+ "exemptions": [
162
+ {
163
+ "rule_id": "cross-domain-db-access",
164
+ "file": "src/legacy/old-service.ts",
165
+ "reason": "Legacy code pending migration",
166
+ "expires": "2026-06-01",
167
+ "adr": "ADR-0042-legacy-migration-plan.md"
168
+ }
169
+ ]
170
+ }
171
+ ```
172
+
173
+ **Rules for Exemptions:**
174
+ - Must reference an ADR
175
+ - Must have expiration date
176
+ - Reviewed monthly
177
+
178
+ ---
179
+
180
+ ## Running Fitness Functions
181
+
182
+ ### Manual Execution
183
+
184
+ ```bash
185
+ # Run in DETECT mode (log violations)
186
+ fitness-enforcer --mode detect
187
+
188
+ # Run in PREVENT mode (block on violations)
189
+ fitness-enforcer --mode prevent
190
+
191
+ # Run for specific files
192
+ fitness-enforcer --files "src/domain-billing/**/*.ts"
193
+ ```
194
+
195
+ ### CI/CD Integration
196
+
197
+ Add to pull request pipeline:
198
+
199
+ ```yaml
200
+ # .github/workflows/fitness.yml
201
+ name: Architectural Fitness
202
+
203
+ on: pull_request
204
+
205
+ jobs:
206
+ fitness:
207
+ runs-on: ubuntu-latest
208
+ steps:
209
+ - uses: actions/checkout@v3
210
+ - name: Run Fitness Enforcer
211
+ run: |
212
+ npm run fitness:enforce
213
+ - name: Upload Report
214
+ uses: actions/upload-artifact@v3
215
+ with:
216
+ name: fitness-report
217
+ path: .ai/reports/fitness-violations.json
218
+ ```
219
+
220
+ ---
221
+
222
+ ## Interpreting Reports
223
+
224
+ ### Sample Report
225
+
226
+ ```json
227
+ {
228
+ "timestamp": "2026-02-24T10:30:00Z",
229
+ "mode": "PREVENT",
230
+ "status": "FAIL",
231
+ "violations": [
232
+ {
233
+ "rule_id": "cross-domain-db-access",
234
+ "severity": "BLOCK",
235
+ "file": "src/domain-billing/services/invoice.service.ts",
236
+ "line": 42,
237
+ "measured_value": "import { PrismaClient } from '@prisma/client'",
238
+ "threshold": 0,
239
+ "remedy": "Use domain-user's public API instead of direct DB access"
240
+ }
241
+ ],
242
+ "metrics": {
243
+ "total_violations": 1,
244
+ "block_violations": 1,
245
+ "warn_violations": 0
246
+ }
247
+ }
248
+ ```
249
+
250
+ **Actions:**
251
+ - `BLOCK` violations → Fix before merge
252
+ - `WARN` violations → Log technical debt, plan remediation
253
+
254
+ ---
255
+
256
+ ## Gradual Adoption
257
+
258
+ For existing codebases with violations:
259
+
260
+ ### Step 1: Baseline
261
+
262
+ ```bash
263
+ fitness-enforcer --mode detect --baseline
264
+ ```
265
+
266
+ Creates `.ai/reports/fitness-baseline.json` with current violation counts.
267
+
268
+ ### Step 2: Prevent New Violations
269
+
270
+ Switch to PREVENT mode but only for **new or modified files**.
271
+
272
+ ### Step 3: Set Reduction Targets
273
+
274
+ Commit to reducing baseline violations by X% per month.
275
+
276
+ ### Step 4: Tighten Thresholds
277
+
278
+ Once violations are controlled, lower thresholds progressively.
279
+
280
+ ---
281
+
282
+ ## Common Violations and Fixes
283
+
284
+ ### Violation: Cross-Domain Database Access
285
+
286
+ **Problem:**
287
+ ```typescript
288
+ // domain-billing accesses domain-user DB directly
289
+ import { PrismaClient } from '@prisma/client';
290
+ const users = await prisma.users.findMany();
291
+ ```
292
+
293
+ **Fix:**
294
+ ```typescript
295
+ // Use domain-user's public service
296
+ import { UserService } from '@/domain-user/services';
297
+ const users = await UserService.getAll();
298
+ ```
299
+
300
+ ### Violation: Too Many Dependencies
301
+
302
+ **Problem:**
303
+ ```typescript
304
+ // god-module.ts has 15 imports
305
+ ```
306
+
307
+ **Fix:**
308
+ - Split into smaller modules by responsibility
309
+ - Extract cross-cutting concerns to shared utilities
310
+
311
+ ### Violation: Presentation Layer Importing Database
312
+
313
+ **Problem:**
314
+ ```typescript
315
+ // React component imports Prisma
316
+ import { PrismaClient } from '@prisma/client';
317
+ ```
318
+
319
+ **Fix:**
320
+ ```typescript
321
+ // Use application layer hook
322
+ import { useUsers } from '@/application/hooks/useUsers';
323
+ ```
324
+
325
+ ---
326
+
327
+ ## Fitness Metrics Dashboard
328
+
329
+ Track architectural health over time.
330
+
331
+ ### Metrics Collected
332
+
333
+ - Total violations (trend)
334
+ - BLOCK vs WARN ratio
335
+ - Dependency graph complexity
336
+ - Module coupling score
337
+ - Domain boundary leak count
338
+
339
+ ### Visualization
340
+
341
+ ```bash
342
+ fitness-enforcer --report dashboard
343
+ ```
344
+
345
+ Generates `.ai/reports/fitness-dashboard.html` with charts.
346
+
347
+ ---
348
+
349
+ ## When to Add New Fitness Functions
350
+
351
+ Add a fitness function when:
352
+
353
+ 1. **Recurring Violation Pattern**
354
+ - Code reviews repeatedly catch the same structural issue
355
+ - Automate the check
356
+
357
+ 2. **ADR Introduces Constraint**
358
+ - ADR mandates architectural rule
359
+ - Encode as fitness function
360
+
361
+ 3. **Architectural Review Recommendation**
362
+ - Architecture Reviewer identifies decay pattern
363
+ - Prevent recurrence with fitness function
364
+
365
+ 4. **Bounded Context Addition**
366
+ - New domain added
367
+ - Enforce boundary isolation
368
+
369
+ ---
370
+
371
+ ## Fitness Function Lifecycle
372
+
373
+ ```
374
+ 1. Identify architectural constraint
375
+
376
+ 2. Encode as fitness rule in rules.json
377
+
378
+ 3. Run in DETECT mode to establish baseline
379
+
380
+ 4. Switch to PREVENT mode for new code
381
+
382
+ 5. Review quarterly — adjust thresholds
383
+ ```
384
+
385
+ ---
386
+
387
+ ## Integration with SHHS
388
+
389
+ Fitness Enforcer runs **after Static Reviewer, before Domain Architect**.
390
+
391
+ ```
392
+ Developer → Static Reviewer → Fitness Enforcer → QA → Domain Architect
393
+ ```
394
+
395
+ **Rationale:** Structural compliance must pass before behavioral testing.
396
+
397
+ ---
398
+
399
+ ## Support
400
+
401
+ For questions on fitness functions:
402
+
403
+ 1. Consult this README
404
+ 2. Review existing rules in `rules.json`
405
+ 3. Check Architecture Review reports in `.ai/architecture/governance/`
406
+ 4. Escalate to Architecture Reviewer for new constraint proposals
407
+
408
+ ---
409
+
410
+ **END OF FITNESS FUNCTIONS GUIDE**
@@ -0,0 +1,48 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft-07/schema",
3
+ "description": "Fitness Enforcer configuration",
4
+ "mode": "DETECT",
5
+ "mode_description": "DETECT mode logs violations but allows merge. PREVENT mode blocks merge on BLOCK-severity violations.",
6
+ "exemptions_enabled": true,
7
+ "metrics_retention_days": 365,
8
+ "report_output": ".ai/reports/fitness-violations.json",
9
+ "trend_analysis_enabled": true,
10
+ "settings": {
11
+ "fail_on_block_violations": false,
12
+ "fail_on_warn_violations": false,
13
+ "generate_html_report": true,
14
+ "html_report_path": ".ai/reports/fitness-dashboard.html",
15
+ "baseline_mode": false,
16
+ "baseline_path": ".ai/reports/fitness-baseline.json"
17
+ },
18
+ "tools": {
19
+ "dependency_analysis": {
20
+ "enabled": true,
21
+ "tool": "madge",
22
+ "options": {
23
+ "circular": true,
24
+ "exclude": "node_modules"
25
+ }
26
+ },
27
+ "complexity_analysis": {
28
+ "enabled": true,
29
+ "tool": "typescript-complexity",
30
+ "options": {
31
+ "threshold": 15
32
+ }
33
+ },
34
+ "import_analysis": {
35
+ "enabled": true,
36
+ "tool": "eslint",
37
+ "options": {
38
+ "parser": "@typescript-eslint/parser"
39
+ }
40
+ }
41
+ },
42
+ "notes": [
43
+ "Start with DETECT mode for baseline establishment",
44
+ "Switch to PREVENT mode once violations are under control",
45
+ "Review exemptions monthly",
46
+ "Adjust thresholds based on trend analysis"
47
+ ]
48
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft-07/schema",
3
+ "description": "Temporary exemptions from fitness rules",
4
+ "exemptions": [],
5
+ "example_exemption": {
6
+ "rule_id": "cross-domain-db-access",
7
+ "file": "src/legacy/old-service.ts",
8
+ "reason": "Legacy code pending migration to new domain architecture",
9
+ "expires": "2026-06-01",
10
+ "adr": "ADR-0042-legacy-migration-plan.md",
11
+ "created_by": "architect@example.com",
12
+ "created_at": "2026-02-24"
13
+ },
14
+ "notes": [
15
+ "All exemptions must reference an ADR",
16
+ "All exemptions must have expiration date",
17
+ "Review exemptions monthly",
18
+ "Max 5 active exemptions per project (prevent abuse)"
19
+ ]
20
+ }
@@ -0,0 +1,102 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft-07/schema",
3
+ "description": "Architectural fitness function rules",
4
+ "rules": [
5
+ {
6
+ "id": "cross-domain-db-access",
7
+ "description": "Domain modules must not directly access other domain databases",
8
+ "condition": {
9
+ "type": "import_pattern",
10
+ "pattern": "src/domain-([^/]+)/.*\\.(ts|js) imports (@prisma/client|typeorm|database).*domain-(?!\\1)[^/]+.*"
11
+ },
12
+ "threshold": 0,
13
+ "severity": "BLOCK",
14
+ "scope": "src/domain-*/**/*.{ts,js}",
15
+ "remedy": "Use the target domain's public service API instead of direct database access. Example: UserService.getOrdersByUser() instead of prisma.user_orders.findMany()"
16
+ },
17
+ {
18
+ "id": "max-module-dependencies",
19
+ "description": "No module may have more than 10 direct dependencies",
20
+ "condition": {
21
+ "type": "dependency_count",
22
+ "target": "file"
23
+ },
24
+ "threshold": 10,
25
+ "severity": "WARN",
26
+ "scope": "src/**/*.{ts,js}",
27
+ "remedy": "Split into smaller, focused modules. Extract cross-cutting concerns to shared utilities."
28
+ },
29
+ {
30
+ "id": "presentation-layer-isolation",
31
+ "description": "Presentation layer must not import database layer",
32
+ "condition": {
33
+ "type": "import_pattern",
34
+ "pattern": "src/presentation/.*\\.(ts|tsx|js|jsx) imports (prisma|typeorm|database|@prisma/client).*"
35
+ },
36
+ "threshold": 0,
37
+ "severity": "BLOCK",
38
+ "scope": "src/presentation/**/*.{ts,tsx,js,jsx}",
39
+ "remedy": "Use application layer hooks or services. Example: useUsers() hook instead of importing PrismaClient."
40
+ },
41
+ {
42
+ "id": "module-centrality",
43
+ "description": "No module may be imported by >30% of codebase (god module detection)",
44
+ "condition": {
45
+ "type": "centrality",
46
+ "metric": "incoming_dependencies_percentage"
47
+ },
48
+ "threshold": 30,
49
+ "severity": "WARN",
50
+ "scope": "src/**/*.{ts,js}",
51
+ "remedy": "Refactor god module into smaller, specialized modules. Consider using dependency inversion."
52
+ },
53
+ {
54
+ "id": "cyclomatic-complexity",
55
+ "description": "Function cyclomatic complexity must not exceed 15",
56
+ "condition": {
57
+ "type": "complexity",
58
+ "metric": "cyclomatic"
59
+ },
60
+ "threshold": 15,
61
+ "severity": "WARN",
62
+ "scope": "src/**/*.{ts,js}",
63
+ "remedy": "Extract complex conditionals into smaller functions. Apply Single Responsibility Principle."
64
+ },
65
+ {
66
+ "id": "no-circular-dependencies",
67
+ "description": "No circular dependencies allowed between modules",
68
+ "condition": {
69
+ "type": "circular_dependency",
70
+ "scope": "module"
71
+ },
72
+ "threshold": 0,
73
+ "severity": "BLOCK",
74
+ "scope": "src/**/*.{ts,js}",
75
+ "remedy": "Break circular dependency by introducing interface/abstraction or restructuring module relationships."
76
+ },
77
+ {
78
+ "id": "infrastructure-layer-isolation",
79
+ "description": "Domain layer must not import infrastructure layer",
80
+ "condition": {
81
+ "type": "import_pattern",
82
+ "pattern": "src/domain/.*\\.(ts|js) imports src/infrastructure/.*"
83
+ },
84
+ "threshold": 0,
85
+ "severity": "BLOCK",
86
+ "scope": "src/domain/**/*.{ts,js}",
87
+ "remedy": "Use dependency inversion. Define interfaces in domain layer, implement in infrastructure."
88
+ },
89
+ {
90
+ "id": "max-file-length",
91
+ "description": "No file should exceed 500 lines (excluding comments)",
92
+ "condition": {
93
+ "type": "file_length",
94
+ "metric": "lines_of_code"
95
+ },
96
+ "threshold": 500,
97
+ "severity": "WARN",
98
+ "scope": "src/**/*.{ts,js,tsx,jsx}",
99
+ "remedy": "Split large files into smaller, cohesive modules."
100
+ }
101
+ ]
102
+ }