nightytidy 0.3.7 → 0.3.9
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.
- package/bin/nightytidy.js +1 -1
- package/package.json +1 -1
- package/src/agent/git-integration.js +4 -1
- package/src/claude.js +1 -1
- package/src/prompts/manifest.json +138 -138
- package/src/prompts/steps/02-test-coverage.md +181 -181
- package/src/prompts/steps/03-test-hardening.md +181 -181
- package/src/prompts/steps/04-test-architecture.md +130 -130
- package/src/prompts/steps/05-test-consolidation.md +165 -165
- package/src/prompts/steps/06-test-quality.md +211 -211
- package/src/prompts/steps/07-api-design.md +165 -165
- package/src/prompts/steps/08-security-sweep.md +207 -207
- package/src/prompts/steps/09-dependency-health.md +217 -217
- package/src/prompts/steps/10-codebase-cleanup.md +189 -189
- package/src/prompts/steps/11-crosscutting-concerns.md +196 -196
- package/src/prompts/steps/12-file-decomposition.md +263 -263
- package/src/prompts/steps/13-code-elegance.md +329 -329
- package/src/prompts/steps/14-architectural-complexity.md +297 -297
- package/src/prompts/steps/15-type-safety.md +192 -192
- package/src/prompts/steps/16-logging-error-message.md +173 -173
- package/src/prompts/steps/17-data-integrity.md +139 -139
- package/src/prompts/steps/18-performance.md +183 -183
- package/src/prompts/steps/19-cost-resource-optimization.md +136 -136
- package/src/prompts/steps/20-error-recovery.md +145 -145
- package/src/prompts/steps/21-race-condition-audit.md +178 -178
- package/src/prompts/steps/22-bug-hunt.md +229 -229
- package/src/prompts/steps/23-frontend-quality.md +210 -210
- package/src/prompts/steps/24-uiux-audit.md +284 -284
- package/src/prompts/steps/25-state-management.md +170 -170
- package/src/prompts/steps/26-perceived-performance.md +190 -190
- package/src/prompts/steps/27-devops.md +165 -165
- package/src/prompts/steps/28-scheduled-job-chron-jobs.md +141 -141
- package/src/prompts/steps/29-observability.md +152 -152
- package/src/prompts/steps/30-backup-check.md +155 -155
- package/src/prompts/steps/31-product-polish-ux-friction.md +122 -122
- package/src/prompts/steps/32-feature-discovery-opportunity.md +128 -128
- package/src/prompts/steps/33-strategic-opportunities.md +217 -217
|
@@ -1,297 +1,297 @@
|
|
|
1
|
-
# Architectural Complexity Audit
|
|
2
|
-
|
|
3
|
-
You are running an overnight architectural complexity audit. Your job: find where the system is more complex than it needs to be — unnecessary indirection, over-abstracted boundaries, convoluted data flows, and astronaut architecture — and produce a prioritized simplification roadmap the team can act on.
|
|
4
|
-
|
|
5
|
-
This is a READ-ONLY analysis. Do not create a branch or modify any code. Architectural simplification requires human judgment about tradeoffs — your job is to surface the complexity, quantify it, and propose specific simplifications with clear risk assessments.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Why This Exists
|
|
10
|
-
|
|
11
|
-
Code Elegance handles function-level complexity: long functions, deep nesting, bad names, mixed abstraction levels within a file. This prompt handles **system-level complexity**: the kind that makes a new developer ask "why does a button click go through 7 files before it reaches the database?" The kind where every feature takes 3x longer to build because you're fighting the architecture instead of using it.
|
|
12
|
-
|
|
13
|
-
Unnecessary complexity is a silent tax. It doesn't show up in bug reports or crash logs. It shows up in slower velocity, harder onboarding, more bugs per feature, and engineers quietly dreading certain parts of the codebase.
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Global Rules
|
|
18
|
-
|
|
19
|
-
- This is READ-ONLY. Do not modify any code or create branches.
|
|
20
|
-
- Be honest about the difference between **unnecessary complexity** (should be simplified) and **essential complexity** (the problem is genuinely hard). Not every abstraction is over-engineering. Some systems are complex because they need to be.
|
|
21
|
-
- When recommending simplification, always state: what you'd remove, what replaces it (or nothing), what capability would be lost (if any), and what would break during the transition.
|
|
22
|
-
- Ground every finding in specifics — file paths, call chains, data flow traces. Not "the auth system is over-engineered" but "a login request passes through 6 files (AuthController → AuthService → AuthProvider → TokenManager → SessionFactory → UserRepository) when AuthController → AuthService → UserRepository would preserve all current behavior."
|
|
23
|
-
- Distinguish between complexity that's hurting the team NOW vs. complexity that was built for future needs that MAY arrive. The latter deserves a lighter touch — flag it, but acknowledge the team may have context you don't.
|
|
24
|
-
- You have all night. Be thorough.
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
## Phase 1: Structural Complexity Mapping
|
|
29
|
-
|
|
30
|
-
### Step 1: Dependency graph analysis
|
|
31
|
-
|
|
32
|
-
Map the import/dependency graph of the entire codebase. Identify:
|
|
33
|
-
|
|
34
|
-
- **Hub modules**: Files imported by 20+ other files. Are they genuine shared utilities, or have they become junk drawers?
|
|
35
|
-
- **Deep dependency chains**: Trace the longest import chains from entry point to leaf module. How many layers does a request pass through? How many are doing meaningful work vs. just forwarding?
|
|
36
|
-
- **Circular dependencies**: Files or modules that import each other, directly or transitively. These almost always indicate confused boundaries.
|
|
37
|
-
- **Orphaned modules**: Files that import from the rest of the codebase but nothing imports them (except possibly tests). Are they dead, or are they entry points?
|
|
38
|
-
|
|
39
|
-
### Step 2: Layer count analysis
|
|
40
|
-
|
|
41
|
-
For each major operation in the system (the core 5-10 user actions), trace the full call path from entry point to data store and back. For each layer traversed, note:
|
|
42
|
-
|
|
43
|
-
- File and function name
|
|
44
|
-
- What meaningful work this layer does (validation? transformation? orchestration? logging? nothing?)
|
|
45
|
-
- Whether removing this layer would change behavior
|
|
46
|
-
|
|
47
|
-
**What you're looking for**: layers that exist for "architectural purity" but don't do meaningful work. A controller that calls a service that calls a repository is fine if each layer has a distinct job. A controller that calls a service that calls a manager that calls a provider that calls a repository — where three of those layers just forward the call — is not.
|
|
48
|
-
|
|
49
|
-
### Step 3: Abstraction inventory
|
|
50
|
-
|
|
51
|
-
Catalog every abstraction mechanism in the codebase:
|
|
52
|
-
|
|
53
|
-
- **Interfaces/abstract classes with one implementation**: These add indirection without flexibility. Flag every one. Note whether tests use an alternate implementation (if yes, the abstraction earns its keep).
|
|
54
|
-
- **Factories that create one type**: A factory that returns `new Thing()` is a function call wearing a hat.
|
|
55
|
-
- **Strategy/plugin patterns with one strategy**: The cost of the pattern isn't justified by one case.
|
|
56
|
-
- **Event/observer systems**: Map every event emitter and every listener. Are events crossing module boundaries (useful) or being used within a single module as a roundabout function call (unnecessary)?
|
|
57
|
-
- **Dependency injection containers**: Is DI used for testability (good) or because "that's how you do it" even where there's nothing to inject and no tests? Map what's injected and whether alternate implementations exist.
|
|
58
|
-
- **Generic/parameterized types with one instantiation**: Generics that are only ever used with one concrete type add cognitive overhead for no flexibility.
|
|
59
|
-
- **Wrapper/adapter classes that don't adapt anything**: Classes that wrap a library with an identical API "in case we switch libraries."
|
|
60
|
-
- **Configuration for things that never change**: Options, settings, and parameters that have had the same value since they were introduced.
|
|
61
|
-
|
|
62
|
-
For each: name it, location, what it abstracts, how many concrete implementations/usages exist, whether removing it would require changing behavior.
|
|
63
|
-
|
|
64
|
-
### Step 4: Directory structure vs. actual architecture
|
|
65
|
-
|
|
66
|
-
- Does the directory structure reflect how the code actually works, or has it drifted?
|
|
67
|
-
- Are related files co-located, or scattered across directories by technical type (all controllers in `/controllers`, all services in `/services`) when they'd be better grouped by feature?
|
|
68
|
-
- Are there directories that have become catch-alls (`/utils`, `/helpers`, `/common`, `/shared`) with 30+ files that have nothing to do with each other?
|
|
69
|
-
- Does the nesting depth of directories match the actual depth of the architecture, or are there 4 levels of folders containing one file each?
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## Phase 2: Data Flow Complexity
|
|
74
|
-
|
|
75
|
-
### Step 1: Trace data transformations
|
|
76
|
-
|
|
77
|
-
For the core data types in the system (users, orders, whatever the domain objects are), trace every transformation from input to storage and from storage to output:
|
|
78
|
-
|
|
79
|
-
- How many times is the data reshaped between API input and database write? (Request DTO → domain model → ORM model → database, for example)
|
|
80
|
-
- How many of those transformations are doing meaningful work (validation, business rules, format conversion) vs. just copying fields between nearly identical shapes?
|
|
81
|
-
- Is the same data serialized and deserialized multiple times unnecessarily?
|
|
82
|
-
- Are there mapping layers that exist only because two adjacent layers chose different field names for the same thing?
|
|
83
|
-
|
|
84
|
-
### Step 2: State management complexity
|
|
85
|
-
|
|
86
|
-
- How many sources of truth exist for key data? (Database, cache, local state, derived state, global store, URL params — how many of these hold the same information?)
|
|
87
|
-
- Where is state duplicated and kept in sync manually? (This is where bugs live.)
|
|
88
|
-
- Is global state used where local state would suffice? (A global store holding form input that's only used in one component.)
|
|
89
|
-
- Are there derived values stored and manually kept in sync instead of computed on demand?
|
|
90
|
-
- Is there a state management library/pattern that's more powerful than what the application needs? (Redux for an app with 3 pages and no shared state.)
|
|
91
|
-
|
|
92
|
-
### Step 3: Configuration complexity
|
|
93
|
-
|
|
94
|
-
- How many configuration layers exist? (Env vars → config files → runtime config → feature flags → database-driven settings → hardcoded defaults scattered through the code)
|
|
95
|
-
- Can you determine what configuration a running instance is actually using without reading 5 files?
|
|
96
|
-
- Are there configurations that override other configurations that override other configurations?
|
|
97
|
-
- Is the same setting configurable in multiple places with unclear precedence?
|
|
98
|
-
|
|
99
|
-
---
|
|
100
|
-
|
|
101
|
-
## Phase 3: Pattern Complexity
|
|
102
|
-
|
|
103
|
-
### Step 1: Premature generalization
|
|
104
|
-
|
|
105
|
-
Find code built for flexibility that was never used:
|
|
106
|
-
|
|
107
|
-
- Multi-tenant infrastructure in a single-tenant app
|
|
108
|
-
- Plugin systems with no plugins
|
|
109
|
-
- Configurable pipelines with one pipeline
|
|
110
|
-
- Abstract base classes designed for "future" subclasses that never arrived
|
|
111
|
-
- Schema versioning for schemas that have never changed
|
|
112
|
-
- Internationalization infrastructure wrapping hardcoded English strings
|
|
113
|
-
- Multi-provider abstractions wrapping a single provider (one payment processor behind a "payment provider" interface, one email service behind an "email provider" interface)
|
|
114
|
-
|
|
115
|
-
For each: when was it introduced (git history)? Has the generalization EVER been used? What's the ongoing maintenance cost?
|
|
116
|
-
|
|
117
|
-
### Step 2: Unnecessary indirection patterns
|
|
118
|
-
|
|
119
|
-
- **Event buses used as function calls**: Module A emits an event that only Module B listens to, and Module A needs to wait for the result. This is a function call with extra steps and lost type safety.
|
|
120
|
-
- **Message queues for synchronous work**: Jobs that are enqueued and then immediately awaited, gaining no benefit from async processing.
|
|
121
|
-
- **HTTP calls between co-located services**: Services that could be function calls but communicate over the network because "they might be separate services someday."
|
|
122
|
-
- **Database as a message broker**: Polling tables for state changes instead of direct communication.
|
|
123
|
-
- **Over-normalized data**: Joins across 6 tables to answer a question that could be a single read if the data were structured differently.
|
|
124
|
-
- **Over-denormalized data**: The same information stored in 4 places, manually kept in sync, leading to inconsistency bugs.
|
|
125
|
-
|
|
126
|
-
### Step 3: Cargo-culted patterns
|
|
127
|
-
|
|
128
|
-
Patterns adopted because they're "best practice" without the context that makes them valuable:
|
|
129
|
-
|
|
130
|
-
- **CQRS without a read/write asymmetry problem**: Separate read and write models doubling the code for a system where reads and writes are similar.
|
|
131
|
-
- **Domain-Driven Design ceremony in a CRUD app**: Aggregates, value objects, domain events, and bounded contexts for an app that reads from a database and shows it on a screen.
|
|
132
|
-
- **Microservice patterns in a monolith**: Service discovery, circuit breakers, and API gateways between modules that run in the same process.
|
|
133
|
-
- **Repository pattern wrapping an ORM**: A repository that exposes `findById`, `findAll`, `save`, `delete` — the exact same interface the ORM already provides, adding a layer that contributes nothing.
|
|
134
|
-
- **Clean Architecture / Hexagonal Architecture over-applied**: Ports, adapters, use cases, and domain layers for a 10-endpoint CRUD API where every "use case" is a one-line call to the repository.
|
|
135
|
-
|
|
136
|
-
For each: what pattern, where it's applied, what problem it's solving (if any), and what the simpler alternative looks like.
|
|
137
|
-
|
|
138
|
-
### Step 4: Accidental complexity from organic growth
|
|
139
|
-
|
|
140
|
-
- Features bolted on that don't fit the original architecture, requiring workarounds
|
|
141
|
-
- Multiple approaches to the same problem coexisting (old way and new way, both maintained)
|
|
142
|
-
- Temporary solutions that became permanent (the `// temporary` comment from 2 years ago)
|
|
143
|
-
- Code that routes around the official architecture because the architecture made the task too hard
|
|
144
|
-
|
|
145
|
-
---
|
|
146
|
-
|
|
147
|
-
## Phase 4: Complexity Quantification
|
|
148
|
-
|
|
149
|
-
### Step 1: Indirection score per operation
|
|
150
|
-
|
|
151
|
-
For each of the core 5-10 user operations, calculate:
|
|
152
|
-
|
|
153
|
-
- **Files touched**: How many files does a request pass through?
|
|
154
|
-
- **Meaningful layers**: How many of those files do meaningful work?
|
|
155
|
-
- **Indirection ratio**: files touched ÷ meaningful layers. An indirection ratio of 1.0 is perfect (every file earns its place). Above 2.0 is a yellow flag. Above 3.0 is a red flag.
|
|
156
|
-
- **Lines of glue code**: Lines that exist only to connect layers (forwarding calls, mapping identical fields, re-exporting).
|
|
157
|
-
|
|
158
|
-
### Step 2: Abstraction overhead inventory
|
|
159
|
-
|
|
160
|
-
Total count of:
|
|
161
|
-
- Interfaces with one implementation
|
|
162
|
-
- Factories creating one type
|
|
163
|
-
- Wrapper classes that don't transform behavior
|
|
164
|
-
- Generic types instantiated with one concrete type
|
|
165
|
-
- Event emissions with one listener
|
|
166
|
-
- Configuration options that have never varied
|
|
167
|
-
|
|
168
|
-
Multiply each by estimated lines of code. This is the **abstraction tax** — code that exists for flexibility that was never used.
|
|
169
|
-
|
|
170
|
-
### Step 3: Onboarding complexity estimate
|
|
171
|
-
|
|
172
|
-
For a new developer to understand enough to make a change in each major area:
|
|
173
|
-
- How many files must they read?
|
|
174
|
-
- How many layers must they understand?
|
|
175
|
-
- How many patterns must they recognize?
|
|
176
|
-
- How many "you just have to know" conventions exist that aren't enforced by the code?
|
|
177
|
-
|
|
178
|
-
Rate each area: **Simple** (read 1-3 files, obvious flow), **Moderate** (5-10 files, patterns to learn), **Complex** (10+ files, significant tribal knowledge), **Labyrinthine** (requires a guide, multiple failed attempts expected).
|
|
179
|
-
|
|
180
|
-
---
|
|
181
|
-
|
|
182
|
-
## Phase 5: Simplification Roadmap
|
|
183
|
-
|
|
184
|
-
### Step 1: Categorize every finding
|
|
185
|
-
|
|
186
|
-
- **Remove**: Abstraction that adds nothing and can be deleted. (Interface with one implementation where no tests use a mock → inline the implementation, delete the interface.)
|
|
187
|
-
- **Collapse**: Multiple layers that can become fewer. (Controller → Service → Manager → Repository where Service and Manager do nothing → Controller → Service → Repository.)
|
|
188
|
-
- **Replace**: Complex pattern that can be swapped for a simpler one. (Event bus between two modules → direct function call.)
|
|
189
|
-
- **Restructure**: Architectural change that would simplify multiple things at once. (Move from technical-layer directories to feature-based directories.)
|
|
190
|
-
- **Accept**: Complexity that's justified by the problem domain or a real future need. Explicitly call these out so the team doesn't waste time re-evaluating them.
|
|
191
|
-
|
|
192
|
-
### Step 2: Risk and effort assessment
|
|
193
|
-
|
|
194
|
-
For each non-Accept finding:
|
|
195
|
-
- **Effort**: Trivial (< 1 hour) / Small (< 1 day) / Medium (< 1 week) / Large (1+ weeks)
|
|
196
|
-
- **Risk**: Low (mechanical, type-safe refactor) / Medium (behavioral edge cases possible) / High (cross-cutting, affects many features)
|
|
197
|
-
- **Impact**: How much simpler does the codebase get? (Lines removed, layers eliminated, onboarding time reduced)
|
|
198
|
-
- **Dependencies**: Does this simplification depend on another simplification happening first?
|
|
199
|
-
- **Test coverage**: Is the area well-tested enough to refactor safely?
|
|
200
|
-
|
|
201
|
-
### Step 3: Prioritized simplification plan
|
|
202
|
-
|
|
203
|
-
Order by: (Impact × Confidence) ÷ (Effort × Risk)
|
|
204
|
-
|
|
205
|
-
Group into:
|
|
206
|
-
- **This week**: Trivial removals with high confidence and good test coverage. Can be done in the next Code Elegance run.
|
|
207
|
-
- **This month**: Small-to-medium simplifications that need planning but not architectural discussion.
|
|
208
|
-
- **This quarter**: Larger restructuring that needs team alignment and incremental execution.
|
|
209
|
-
- **Backlog**: Good ideas that aren't worth doing until something else forces the issue.
|
|
210
|
-
|
|
211
|
-
---
|
|
212
|
-
|
|
213
|
-
## Output
|
|
214
|
-
|
|
215
|
-
Create `audit-reports/` in project root if needed. Save as `audit-reports/14_ARCHITECTURAL_COMPLEXITY_REPORT_[run-number]_[date]_[time in user's local time].md`, incrementing run number based on existing reports.
|
|
216
|
-
|
|
217
|
-
### Report Structure
|
|
218
|
-
|
|
219
|
-
1. **Executive Summary** — Overall complexity assessment (lean / reasonable / heavy / over-engineered), the single biggest complexity tax the codebase is paying, top 3 simplification opportunities with estimated impact.
|
|
220
|
-
|
|
221
|
-
2. **Structural Complexity Map**
|
|
222
|
-
- Dependency graph summary: hub modules, deepest chains, circular dependencies
|
|
223
|
-
- Layer analysis per operation: | Operation | Files Touched | Meaningful Layers | Indirection Ratio | Glue Code Lines |
|
|
224
|
-
- Abstraction inventory: | Abstraction | Type | Location | Implementations | Justification | Verdict |
|
|
225
|
-
- Directory structure assessment
|
|
226
|
-
|
|
227
|
-
3. **Data Flow Complexity**
|
|
228
|
-
- Transformation chains per core data type: diagram or table showing each reshape and whether it does meaningful work
|
|
229
|
-
- State management assessment: sources of truth, duplication, global vs. local
|
|
230
|
-
- Configuration layer map
|
|
231
|
-
|
|
232
|
-
4. **Pattern Complexity**
|
|
233
|
-
- Premature generalizations: | Pattern | Location | Introduced | Ever Used? | Maintenance Cost | Recommendation |
|
|
234
|
-
- Unnecessary indirection: | Pattern | Location | Simpler Alternative | Risk of Change |
|
|
235
|
-
- Cargo-culted patterns: | Pattern | Location | Problem It Solves Here | Simpler Alternative |
|
|
236
|
-
- Organic growth tangles: locations where the architecture has been routed around
|
|
237
|
-
|
|
238
|
-
5. **Complexity Quantification**
|
|
239
|
-
- Indirection scores per operation (table + red/yellow/green)
|
|
240
|
-
- Abstraction overhead: total line count, percentage of codebase
|
|
241
|
-
- Onboarding complexity per area: | Area | Files to Read | Layers | Patterns | Rating |
|
|
242
|
-
|
|
243
|
-
6. **Simplification Roadmap**
|
|
244
|
-
- Full finding list: | Finding | Category (Remove/Collapse/Replace/Restructure/Accept) | Effort | Risk | Impact | Priority |
|
|
245
|
-
- This week: trivial removals, feed into next Code Elegance or Codebase Cleanup run
|
|
246
|
-
- This month: planned simplifications with suggested approach
|
|
247
|
-
- This quarter: larger restructuring with milestones
|
|
248
|
-
- Backlog: good ideas, low urgency
|
|
249
|
-
- Dependency graph between simplifications (what enables what)
|
|
250
|
-
|
|
251
|
-
7. **Accepted Complexity**
|
|
252
|
-
- Complexity that's justified, with explicit reasoning. This section exists so the team doesn't re-litigate these decisions.
|
|
253
|
-
|
|
254
|
-
8. **Recommendations**
|
|
255
|
-
- Priority-ordered next steps
|
|
256
|
-
- Which existing overnight prompts (Code Elegance, File Decomposition, Codebase Cleanup) should run next and what they should target based on these findings
|
|
257
|
-
- Conventions to adopt to prevent new unnecessary complexity
|
|
258
|
-
- How to evaluate "should we add this abstraction?" going forward (a decision framework)
|
|
259
|
-
|
|
260
|
-
## Rules
|
|
261
|
-
- READ-ONLY. Do not modify any code.
|
|
262
|
-
- Be specific. Every finding must include file paths, call chains, or data flow traces — not just categories.
|
|
263
|
-
- Distinguish essential complexity from accidental complexity. Complex domain logic is not over-engineering.
|
|
264
|
-
- Respect that you may lack context. The team may have plans that justify abstractions you'd flag. Frame recommendations as "based on what I can see in the codebase" and mark assumptions.
|
|
265
|
-
- Don't recommend simplification that would sacrifice testability. If an abstraction exists solely to enable testing, that's a valid reason to keep it — note it as such.
|
|
266
|
-
- Don't conflate "I'd write it differently" with "this is unnecessarily complex." The bar is: does this complexity serve a purpose that justifies its cost?
|
|
267
|
-
- Use git history when available to understand whether abstractions were built for growth that materialized or growth that didn't.
|
|
268
|
-
- You have all night. Trace every major code path. Check every abstraction.
|
|
269
|
-
|
|
270
|
-
## Chat Output Requirement
|
|
271
|
-
|
|
272
|
-
In addition to writing the full report file, you MUST print a summary directly in the conversation when you finish. Do not make the user open the report to get the highlights. The chat summary should include:
|
|
273
|
-
|
|
274
|
-
### 1. Status Line
|
|
275
|
-
One sentence: what you did and how long it took.
|
|
276
|
-
|
|
277
|
-
### 2. Key Findings
|
|
278
|
-
The most important complexity hotspots discovered. Each bullet should be specific and actionable, not vague. Lead with impact.
|
|
279
|
-
|
|
280
|
-
**Good:** "The order creation flow passes through 9 files (OrderController → OrderValidator → OrderService → OrderOrchestrator → InventoryManager → PricingEngine → PaymentProvider → OrderRepository → AuditLogger) but only 4 do meaningful work — the other 5 are pure forwarding layers. Collapsing to 4 layers would remove ~600 lines of glue code and cut onboarding time for this flow in half."
|
|
281
|
-
**Bad:** "Found some unnecessary abstraction layers."
|
|
282
|
-
|
|
283
|
-
### 3. Simplification Roadmap
|
|
284
|
-
The full prioritized list of simplification opportunities from the report, grouped by timeframe (this week / this month / this quarter / backlog). Each item should include: what to simplify, category (Remove/Collapse/Replace/Restructure), risk level, and expected impact. Do not truncate — the user should be able to act on this list without opening the report.
|
|
285
|
-
|
|
286
|
-
### 4. Accepted Complexity
|
|
287
|
-
Briefly list any complexity you evaluated and determined is justified, so the team doesn't re-investigate it.
|
|
288
|
-
|
|
289
|
-
### 5. Report Location
|
|
290
|
-
State the full path to the detailed report file for deeper review.
|
|
291
|
-
|
|
292
|
-
---
|
|
293
|
-
|
|
294
|
-
**Formatting rules for chat output:**
|
|
295
|
-
- Use markdown headers, bold for severity labels, and bullet points for scannability.
|
|
296
|
-
- Do not duplicate the full report contents — just the highlights and top recommendations.
|
|
297
|
-
- If you made zero findings in a phase, say so in one line rather than omitting it silently.
|
|
1
|
+
# Architectural Complexity Audit
|
|
2
|
+
|
|
3
|
+
You are running an overnight architectural complexity audit. Your job: find where the system is more complex than it needs to be — unnecessary indirection, over-abstracted boundaries, convoluted data flows, and astronaut architecture — and produce a prioritized simplification roadmap the team can act on.
|
|
4
|
+
|
|
5
|
+
This is a READ-ONLY analysis. Do not create a branch or modify any code. Architectural simplification requires human judgment about tradeoffs — your job is to surface the complexity, quantify it, and propose specific simplifications with clear risk assessments.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Why This Exists
|
|
10
|
+
|
|
11
|
+
Code Elegance handles function-level complexity: long functions, deep nesting, bad names, mixed abstraction levels within a file. This prompt handles **system-level complexity**: the kind that makes a new developer ask "why does a button click go through 7 files before it reaches the database?" The kind where every feature takes 3x longer to build because you're fighting the architecture instead of using it.
|
|
12
|
+
|
|
13
|
+
Unnecessary complexity is a silent tax. It doesn't show up in bug reports or crash logs. It shows up in slower velocity, harder onboarding, more bugs per feature, and engineers quietly dreading certain parts of the codebase.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Global Rules
|
|
18
|
+
|
|
19
|
+
- This is READ-ONLY. Do not modify any code or create branches.
|
|
20
|
+
- Be honest about the difference between **unnecessary complexity** (should be simplified) and **essential complexity** (the problem is genuinely hard). Not every abstraction is over-engineering. Some systems are complex because they need to be.
|
|
21
|
+
- When recommending simplification, always state: what you'd remove, what replaces it (or nothing), what capability would be lost (if any), and what would break during the transition.
|
|
22
|
+
- Ground every finding in specifics — file paths, call chains, data flow traces. Not "the auth system is over-engineered" but "a login request passes through 6 files (AuthController → AuthService → AuthProvider → TokenManager → SessionFactory → UserRepository) when AuthController → AuthService → UserRepository would preserve all current behavior."
|
|
23
|
+
- Distinguish between complexity that's hurting the team NOW vs. complexity that was built for future needs that MAY arrive. The latter deserves a lighter touch — flag it, but acknowledge the team may have context you don't.
|
|
24
|
+
- You have all night. Be thorough.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Phase 1: Structural Complexity Mapping
|
|
29
|
+
|
|
30
|
+
### Step 1: Dependency graph analysis
|
|
31
|
+
|
|
32
|
+
Map the import/dependency graph of the entire codebase. Identify:
|
|
33
|
+
|
|
34
|
+
- **Hub modules**: Files imported by 20+ other files. Are they genuine shared utilities, or have they become junk drawers?
|
|
35
|
+
- **Deep dependency chains**: Trace the longest import chains from entry point to leaf module. How many layers does a request pass through? How many are doing meaningful work vs. just forwarding?
|
|
36
|
+
- **Circular dependencies**: Files or modules that import each other, directly or transitively. These almost always indicate confused boundaries.
|
|
37
|
+
- **Orphaned modules**: Files that import from the rest of the codebase but nothing imports them (except possibly tests). Are they dead, or are they entry points?
|
|
38
|
+
|
|
39
|
+
### Step 2: Layer count analysis
|
|
40
|
+
|
|
41
|
+
For each major operation in the system (the core 5-10 user actions), trace the full call path from entry point to data store and back. For each layer traversed, note:
|
|
42
|
+
|
|
43
|
+
- File and function name
|
|
44
|
+
- What meaningful work this layer does (validation? transformation? orchestration? logging? nothing?)
|
|
45
|
+
- Whether removing this layer would change behavior
|
|
46
|
+
|
|
47
|
+
**What you're looking for**: layers that exist for "architectural purity" but don't do meaningful work. A controller that calls a service that calls a repository is fine if each layer has a distinct job. A controller that calls a service that calls a manager that calls a provider that calls a repository — where three of those layers just forward the call — is not.
|
|
48
|
+
|
|
49
|
+
### Step 3: Abstraction inventory
|
|
50
|
+
|
|
51
|
+
Catalog every abstraction mechanism in the codebase:
|
|
52
|
+
|
|
53
|
+
- **Interfaces/abstract classes with one implementation**: These add indirection without flexibility. Flag every one. Note whether tests use an alternate implementation (if yes, the abstraction earns its keep).
|
|
54
|
+
- **Factories that create one type**: A factory that returns `new Thing()` is a function call wearing a hat.
|
|
55
|
+
- **Strategy/plugin patterns with one strategy**: The cost of the pattern isn't justified by one case.
|
|
56
|
+
- **Event/observer systems**: Map every event emitter and every listener. Are events crossing module boundaries (useful) or being used within a single module as a roundabout function call (unnecessary)?
|
|
57
|
+
- **Dependency injection containers**: Is DI used for testability (good) or because "that's how you do it" even where there's nothing to inject and no tests? Map what's injected and whether alternate implementations exist.
|
|
58
|
+
- **Generic/parameterized types with one instantiation**: Generics that are only ever used with one concrete type add cognitive overhead for no flexibility.
|
|
59
|
+
- **Wrapper/adapter classes that don't adapt anything**: Classes that wrap a library with an identical API "in case we switch libraries."
|
|
60
|
+
- **Configuration for things that never change**: Options, settings, and parameters that have had the same value since they were introduced.
|
|
61
|
+
|
|
62
|
+
For each: name it, location, what it abstracts, how many concrete implementations/usages exist, whether removing it would require changing behavior.
|
|
63
|
+
|
|
64
|
+
### Step 4: Directory structure vs. actual architecture
|
|
65
|
+
|
|
66
|
+
- Does the directory structure reflect how the code actually works, or has it drifted?
|
|
67
|
+
- Are related files co-located, or scattered across directories by technical type (all controllers in `/controllers`, all services in `/services`) when they'd be better grouped by feature?
|
|
68
|
+
- Are there directories that have become catch-alls (`/utils`, `/helpers`, `/common`, `/shared`) with 30+ files that have nothing to do with each other?
|
|
69
|
+
- Does the nesting depth of directories match the actual depth of the architecture, or are there 4 levels of folders containing one file each?
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Phase 2: Data Flow Complexity
|
|
74
|
+
|
|
75
|
+
### Step 1: Trace data transformations
|
|
76
|
+
|
|
77
|
+
For the core data types in the system (users, orders, whatever the domain objects are), trace every transformation from input to storage and from storage to output:
|
|
78
|
+
|
|
79
|
+
- How many times is the data reshaped between API input and database write? (Request DTO → domain model → ORM model → database, for example)
|
|
80
|
+
- How many of those transformations are doing meaningful work (validation, business rules, format conversion) vs. just copying fields between nearly identical shapes?
|
|
81
|
+
- Is the same data serialized and deserialized multiple times unnecessarily?
|
|
82
|
+
- Are there mapping layers that exist only because two adjacent layers chose different field names for the same thing?
|
|
83
|
+
|
|
84
|
+
### Step 2: State management complexity
|
|
85
|
+
|
|
86
|
+
- How many sources of truth exist for key data? (Database, cache, local state, derived state, global store, URL params — how many of these hold the same information?)
|
|
87
|
+
- Where is state duplicated and kept in sync manually? (This is where bugs live.)
|
|
88
|
+
- Is global state used where local state would suffice? (A global store holding form input that's only used in one component.)
|
|
89
|
+
- Are there derived values stored and manually kept in sync instead of computed on demand?
|
|
90
|
+
- Is there a state management library/pattern that's more powerful than what the application needs? (Redux for an app with 3 pages and no shared state.)
|
|
91
|
+
|
|
92
|
+
### Step 3: Configuration complexity
|
|
93
|
+
|
|
94
|
+
- How many configuration layers exist? (Env vars → config files → runtime config → feature flags → database-driven settings → hardcoded defaults scattered through the code)
|
|
95
|
+
- Can you determine what configuration a running instance is actually using without reading 5 files?
|
|
96
|
+
- Are there configurations that override other configurations that override other configurations?
|
|
97
|
+
- Is the same setting configurable in multiple places with unclear precedence?
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Phase 3: Pattern Complexity
|
|
102
|
+
|
|
103
|
+
### Step 1: Premature generalization
|
|
104
|
+
|
|
105
|
+
Find code built for flexibility that was never used:
|
|
106
|
+
|
|
107
|
+
- Multi-tenant infrastructure in a single-tenant app
|
|
108
|
+
- Plugin systems with no plugins
|
|
109
|
+
- Configurable pipelines with one pipeline
|
|
110
|
+
- Abstract base classes designed for "future" subclasses that never arrived
|
|
111
|
+
- Schema versioning for schemas that have never changed
|
|
112
|
+
- Internationalization infrastructure wrapping hardcoded English strings
|
|
113
|
+
- Multi-provider abstractions wrapping a single provider (one payment processor behind a "payment provider" interface, one email service behind an "email provider" interface)
|
|
114
|
+
|
|
115
|
+
For each: when was it introduced (git history)? Has the generalization EVER been used? What's the ongoing maintenance cost?
|
|
116
|
+
|
|
117
|
+
### Step 2: Unnecessary indirection patterns
|
|
118
|
+
|
|
119
|
+
- **Event buses used as function calls**: Module A emits an event that only Module B listens to, and Module A needs to wait for the result. This is a function call with extra steps and lost type safety.
|
|
120
|
+
- **Message queues for synchronous work**: Jobs that are enqueued and then immediately awaited, gaining no benefit from async processing.
|
|
121
|
+
- **HTTP calls between co-located services**: Services that could be function calls but communicate over the network because "they might be separate services someday."
|
|
122
|
+
- **Database as a message broker**: Polling tables for state changes instead of direct communication.
|
|
123
|
+
- **Over-normalized data**: Joins across 6 tables to answer a question that could be a single read if the data were structured differently.
|
|
124
|
+
- **Over-denormalized data**: The same information stored in 4 places, manually kept in sync, leading to inconsistency bugs.
|
|
125
|
+
|
|
126
|
+
### Step 3: Cargo-culted patterns
|
|
127
|
+
|
|
128
|
+
Patterns adopted because they're "best practice" without the context that makes them valuable:
|
|
129
|
+
|
|
130
|
+
- **CQRS without a read/write asymmetry problem**: Separate read and write models doubling the code for a system where reads and writes are similar.
|
|
131
|
+
- **Domain-Driven Design ceremony in a CRUD app**: Aggregates, value objects, domain events, and bounded contexts for an app that reads from a database and shows it on a screen.
|
|
132
|
+
- **Microservice patterns in a monolith**: Service discovery, circuit breakers, and API gateways between modules that run in the same process.
|
|
133
|
+
- **Repository pattern wrapping an ORM**: A repository that exposes `findById`, `findAll`, `save`, `delete` — the exact same interface the ORM already provides, adding a layer that contributes nothing.
|
|
134
|
+
- **Clean Architecture / Hexagonal Architecture over-applied**: Ports, adapters, use cases, and domain layers for a 10-endpoint CRUD API where every "use case" is a one-line call to the repository.
|
|
135
|
+
|
|
136
|
+
For each: what pattern, where it's applied, what problem it's solving (if any), and what the simpler alternative looks like.
|
|
137
|
+
|
|
138
|
+
### Step 4: Accidental complexity from organic growth
|
|
139
|
+
|
|
140
|
+
- Features bolted on that don't fit the original architecture, requiring workarounds
|
|
141
|
+
- Multiple approaches to the same problem coexisting (old way and new way, both maintained)
|
|
142
|
+
- Temporary solutions that became permanent (the `// temporary` comment from 2 years ago)
|
|
143
|
+
- Code that routes around the official architecture because the architecture made the task too hard
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Phase 4: Complexity Quantification
|
|
148
|
+
|
|
149
|
+
### Step 1: Indirection score per operation
|
|
150
|
+
|
|
151
|
+
For each of the core 5-10 user operations, calculate:
|
|
152
|
+
|
|
153
|
+
- **Files touched**: How many files does a request pass through?
|
|
154
|
+
- **Meaningful layers**: How many of those files do meaningful work?
|
|
155
|
+
- **Indirection ratio**: files touched ÷ meaningful layers. An indirection ratio of 1.0 is perfect (every file earns its place). Above 2.0 is a yellow flag. Above 3.0 is a red flag.
|
|
156
|
+
- **Lines of glue code**: Lines that exist only to connect layers (forwarding calls, mapping identical fields, re-exporting).
|
|
157
|
+
|
|
158
|
+
### Step 2: Abstraction overhead inventory
|
|
159
|
+
|
|
160
|
+
Total count of:
|
|
161
|
+
- Interfaces with one implementation
|
|
162
|
+
- Factories creating one type
|
|
163
|
+
- Wrapper classes that don't transform behavior
|
|
164
|
+
- Generic types instantiated with one concrete type
|
|
165
|
+
- Event emissions with one listener
|
|
166
|
+
- Configuration options that have never varied
|
|
167
|
+
|
|
168
|
+
Multiply each by estimated lines of code. This is the **abstraction tax** — code that exists for flexibility that was never used.
|
|
169
|
+
|
|
170
|
+
### Step 3: Onboarding complexity estimate
|
|
171
|
+
|
|
172
|
+
For a new developer to understand enough to make a change in each major area:
|
|
173
|
+
- How many files must they read?
|
|
174
|
+
- How many layers must they understand?
|
|
175
|
+
- How many patterns must they recognize?
|
|
176
|
+
- How many "you just have to know" conventions exist that aren't enforced by the code?
|
|
177
|
+
|
|
178
|
+
Rate each area: **Simple** (read 1-3 files, obvious flow), **Moderate** (5-10 files, patterns to learn), **Complex** (10+ files, significant tribal knowledge), **Labyrinthine** (requires a guide, multiple failed attempts expected).
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Phase 5: Simplification Roadmap
|
|
183
|
+
|
|
184
|
+
### Step 1: Categorize every finding
|
|
185
|
+
|
|
186
|
+
- **Remove**: Abstraction that adds nothing and can be deleted. (Interface with one implementation where no tests use a mock → inline the implementation, delete the interface.)
|
|
187
|
+
- **Collapse**: Multiple layers that can become fewer. (Controller → Service → Manager → Repository where Service and Manager do nothing → Controller → Service → Repository.)
|
|
188
|
+
- **Replace**: Complex pattern that can be swapped for a simpler one. (Event bus between two modules → direct function call.)
|
|
189
|
+
- **Restructure**: Architectural change that would simplify multiple things at once. (Move from technical-layer directories to feature-based directories.)
|
|
190
|
+
- **Accept**: Complexity that's justified by the problem domain or a real future need. Explicitly call these out so the team doesn't waste time re-evaluating them.
|
|
191
|
+
|
|
192
|
+
### Step 2: Risk and effort assessment
|
|
193
|
+
|
|
194
|
+
For each non-Accept finding:
|
|
195
|
+
- **Effort**: Trivial (< 1 hour) / Small (< 1 day) / Medium (< 1 week) / Large (1+ weeks)
|
|
196
|
+
- **Risk**: Low (mechanical, type-safe refactor) / Medium (behavioral edge cases possible) / High (cross-cutting, affects many features)
|
|
197
|
+
- **Impact**: How much simpler does the codebase get? (Lines removed, layers eliminated, onboarding time reduced)
|
|
198
|
+
- **Dependencies**: Does this simplification depend on another simplification happening first?
|
|
199
|
+
- **Test coverage**: Is the area well-tested enough to refactor safely?
|
|
200
|
+
|
|
201
|
+
### Step 3: Prioritized simplification plan
|
|
202
|
+
|
|
203
|
+
Order by: (Impact × Confidence) ÷ (Effort × Risk)
|
|
204
|
+
|
|
205
|
+
Group into:
|
|
206
|
+
- **This week**: Trivial removals with high confidence and good test coverage. Can be done in the next Code Elegance run.
|
|
207
|
+
- **This month**: Small-to-medium simplifications that need planning but not architectural discussion.
|
|
208
|
+
- **This quarter**: Larger restructuring that needs team alignment and incremental execution.
|
|
209
|
+
- **Backlog**: Good ideas that aren't worth doing until something else forces the issue.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Output
|
|
214
|
+
|
|
215
|
+
Create `audit-reports/` in project root if needed. Save as `audit-reports/14_ARCHITECTURAL_COMPLEXITY_REPORT_[run-number]_[date]_[time in user's local time].md`, incrementing run number based on existing reports.
|
|
216
|
+
|
|
217
|
+
### Report Structure
|
|
218
|
+
|
|
219
|
+
1. **Executive Summary** — Overall complexity assessment (lean / reasonable / heavy / over-engineered), the single biggest complexity tax the codebase is paying, top 3 simplification opportunities with estimated impact.
|
|
220
|
+
|
|
221
|
+
2. **Structural Complexity Map**
|
|
222
|
+
- Dependency graph summary: hub modules, deepest chains, circular dependencies
|
|
223
|
+
- Layer analysis per operation: | Operation | Files Touched | Meaningful Layers | Indirection Ratio | Glue Code Lines |
|
|
224
|
+
- Abstraction inventory: | Abstraction | Type | Location | Implementations | Justification | Verdict |
|
|
225
|
+
- Directory structure assessment
|
|
226
|
+
|
|
227
|
+
3. **Data Flow Complexity**
|
|
228
|
+
- Transformation chains per core data type: diagram or table showing each reshape and whether it does meaningful work
|
|
229
|
+
- State management assessment: sources of truth, duplication, global vs. local
|
|
230
|
+
- Configuration layer map
|
|
231
|
+
|
|
232
|
+
4. **Pattern Complexity**
|
|
233
|
+
- Premature generalizations: | Pattern | Location | Introduced | Ever Used? | Maintenance Cost | Recommendation |
|
|
234
|
+
- Unnecessary indirection: | Pattern | Location | Simpler Alternative | Risk of Change |
|
|
235
|
+
- Cargo-culted patterns: | Pattern | Location | Problem It Solves Here | Simpler Alternative |
|
|
236
|
+
- Organic growth tangles: locations where the architecture has been routed around
|
|
237
|
+
|
|
238
|
+
5. **Complexity Quantification**
|
|
239
|
+
- Indirection scores per operation (table + red/yellow/green)
|
|
240
|
+
- Abstraction overhead: total line count, percentage of codebase
|
|
241
|
+
- Onboarding complexity per area: | Area | Files to Read | Layers | Patterns | Rating |
|
|
242
|
+
|
|
243
|
+
6. **Simplification Roadmap**
|
|
244
|
+
- Full finding list: | Finding | Category (Remove/Collapse/Replace/Restructure/Accept) | Effort | Risk | Impact | Priority |
|
|
245
|
+
- This week: trivial removals, feed into next Code Elegance or Codebase Cleanup run
|
|
246
|
+
- This month: planned simplifications with suggested approach
|
|
247
|
+
- This quarter: larger restructuring with milestones
|
|
248
|
+
- Backlog: good ideas, low urgency
|
|
249
|
+
- Dependency graph between simplifications (what enables what)
|
|
250
|
+
|
|
251
|
+
7. **Accepted Complexity**
|
|
252
|
+
- Complexity that's justified, with explicit reasoning. This section exists so the team doesn't re-litigate these decisions.
|
|
253
|
+
|
|
254
|
+
8. **Recommendations**
|
|
255
|
+
- Priority-ordered next steps
|
|
256
|
+
- Which existing overnight prompts (Code Elegance, File Decomposition, Codebase Cleanup) should run next and what they should target based on these findings
|
|
257
|
+
- Conventions to adopt to prevent new unnecessary complexity
|
|
258
|
+
- How to evaluate "should we add this abstraction?" going forward (a decision framework)
|
|
259
|
+
|
|
260
|
+
## Rules
|
|
261
|
+
- READ-ONLY. Do not modify any code.
|
|
262
|
+
- Be specific. Every finding must include file paths, call chains, or data flow traces — not just categories.
|
|
263
|
+
- Distinguish essential complexity from accidental complexity. Complex domain logic is not over-engineering.
|
|
264
|
+
- Respect that you may lack context. The team may have plans that justify abstractions you'd flag. Frame recommendations as "based on what I can see in the codebase" and mark assumptions.
|
|
265
|
+
- Don't recommend simplification that would sacrifice testability. If an abstraction exists solely to enable testing, that's a valid reason to keep it — note it as such.
|
|
266
|
+
- Don't conflate "I'd write it differently" with "this is unnecessarily complex." The bar is: does this complexity serve a purpose that justifies its cost?
|
|
267
|
+
- Use git history when available to understand whether abstractions were built for growth that materialized or growth that didn't.
|
|
268
|
+
- You have all night. Trace every major code path. Check every abstraction.
|
|
269
|
+
|
|
270
|
+
## Chat Output Requirement
|
|
271
|
+
|
|
272
|
+
In addition to writing the full report file, you MUST print a summary directly in the conversation when you finish. Do not make the user open the report to get the highlights. The chat summary should include:
|
|
273
|
+
|
|
274
|
+
### 1. Status Line
|
|
275
|
+
One sentence: what you did and how long it took.
|
|
276
|
+
|
|
277
|
+
### 2. Key Findings
|
|
278
|
+
The most important complexity hotspots discovered. Each bullet should be specific and actionable, not vague. Lead with impact.
|
|
279
|
+
|
|
280
|
+
**Good:** "The order creation flow passes through 9 files (OrderController → OrderValidator → OrderService → OrderOrchestrator → InventoryManager → PricingEngine → PaymentProvider → OrderRepository → AuditLogger) but only 4 do meaningful work — the other 5 are pure forwarding layers. Collapsing to 4 layers would remove ~600 lines of glue code and cut onboarding time for this flow in half."
|
|
281
|
+
**Bad:** "Found some unnecessary abstraction layers."
|
|
282
|
+
|
|
283
|
+
### 3. Simplification Roadmap
|
|
284
|
+
The full prioritized list of simplification opportunities from the report, grouped by timeframe (this week / this month / this quarter / backlog). Each item should include: what to simplify, category (Remove/Collapse/Replace/Restructure), risk level, and expected impact. Do not truncate — the user should be able to act on this list without opening the report.
|
|
285
|
+
|
|
286
|
+
### 4. Accepted Complexity
|
|
287
|
+
Briefly list any complexity you evaluated and determined is justified, so the team doesn't re-investigate it.
|
|
288
|
+
|
|
289
|
+
### 5. Report Location
|
|
290
|
+
State the full path to the detailed report file for deeper review.
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
**Formatting rules for chat output:**
|
|
295
|
+
- Use markdown headers, bold for severity labels, and bullet points for scannability.
|
|
296
|
+
- Do not duplicate the full report contents — just the highlights and top recommendations.
|
|
297
|
+
- If you made zero findings in a phase, say so in one line rather than omitting it silently.
|