Add Fitness Functions
Add architectural fitness functions to HARNESS.md as weekly GC rules that detect system-wide degradation — layer boundary violations, rising coupling, and complexity hotspots — that per-change constraints miss.
1. Identify what to measure
Fitness functions answer “Is the system still healthy?” at a system-wide level. Pick checks from these categories:
| Category | Examples |
|---|---|
| Structural | Layer boundary violations, circular dependencies |
| Coupling | Fan-in/fan-out growth, instability index changes |
| Complexity | Files with high churn correlated with growing complexity |
| Coverage | Test coverage declining in architecturally important layers |
Start with one structural check. Add coupling or complexity checks after the first is running reliably.
2. Pick a tool for your stack
| Stack | Tool | Install |
|---|---|---|
| JavaScript/TypeScript | dependency-cruiser | npm install --save-dev dependency-cruiser |
| Java/Kotlin | ArchUnit | Add to build dependencies |
| Go | go-cleanarch | go install github.com/roblaszczak/go-cleanarch@latest |
| Python | import-linter | pip install import-linter |
| Any language | semgrep | brew install semgrep |
Verify the tool works against your codebase before wiring it into the harness:
# JavaScript example
npx dependency-cruiser --validate .dependency-cruiser.js src/
# Go example
go-cleanarch -application app -domain domain -infrastructure infra ./...
The tool should exit non-zero when a violation is present.
3. Add a GC rule to HARNESS.md
Open HARNESS.md and add an entry to the Garbage Collection section. Use deterministic when the tool produces a clear pass/fail, and agent when results need trend interpretation:
### Layer boundary compliance
- **What it checks**: No imports crossing declared architectural boundaries
- **Frequency**: weekly
- **Enforcement**: deterministic
- **Tool**: npx dependency-cruiser --validate .dependency-cruiser.js src/
- **Auto-fix**: false
For checks that produce metrics rather than pass/fail (coupling trends, complexity scores), use agent enforcement:
### Coupling trend
- **What it checks**: Inter-module coupling has not increased since last snapshot
- **Frequency**: weekly
- **Enforcement**: agent
- **Tool**: npx dependency-cruiser --output-type metrics src/
- **Auto-fix**: false
Keep Auto-fix as false for all fitness functions. Architectural issues require human judgement about the right fix.
4. Run the fitness function manually
Before relying on the scheduled GC run, confirm the rule works:
/harness-gc
The GC agent reads the weekly rules from HARNESS.md, executes each tool command, and reports findings. Review the output to confirm your new rule fires correctly.
5. Interpret the results
Fitness functions produce trend data, not binary pass/fail. Use this table:
| Trend | Action |
|---|---|
| Stable or improving | Record the snapshot, no action needed |
| Slow decline (1-2 snapshots) | Note it; watch next week |
| Sustained decline (3+ snapshots) | Create an issue with the trend data |
| Sudden spike | Investigate commits since the last snapshot |
6. Promote to a constraint if needed
If the same violation appears in three or more consecutive weekly snapshots, promote it to a per-PR constraint so it blocks new violations at merge time:
- Extract the specific pattern from the fitness function
- Run
/harness-constrainto add a targeted constraint in HARNESS.md - Set scope to
prand enforcement todeterministic - Keep the broader fitness function running — it catches drift the narrower constraint does not