refactor-radar · diff
git:20260618.e501626 to git:20260908.0c0074f
12 added, 12 removed. Audit A to A.
---
name: refactor-radar
description: >
AI self-monitoring skill. Detects architectural debt, confusing schemas, inconsistent patterns that
cause repeated AI mistakes. Offers to create refactoring proposals as issues. NOT user-invoked -
AI triggers when detecting systemic codebase issues causing confusion.
---
# Refactor Radar
Detects systemic codebase issues that repeatedly confuse AI assistants and offers to create refactoring proposals.
## When to Trigger (Self-Assessment)
**IMPORTANT:** This skill is NOT user-invoked. Trigger when you detect patterns that will cause ONGOING confusion, not one-time mistakes.
### Architectural Smells (High Confidence)
1. **Inconsistent Naming Across Layers** [category: `naming`]
- DB uses snake_case, API uses camelCase, frontend uses kebab-case
- Same concept has different names in different places (`user`, `account`, `member`)
- Example: `users.created_at` → API returns `createdAt` → Frontend displays `creation-date`
2. **Schema/Model Mismatch** [category: `schema`]
- ORM models don't match actual DB schema
- TypeScript types don't match API responses
- Documentation describes different structure than code
- Example: Type says `user.email: string` but DB allows null
3. **Inconsistent Patterns in Same Codebase** [category: `patterns`]
- Some services use Repository pattern, others direct DB access
- Mixed async patterns (callbacks, promises, async/await)
- Multiple state management approaches in same frontend
- Example: `/api/users` uses REST, `/api/orders` uses GraphQL
4. **Ambiguous or Misleading Names** [category: `naming`]
- `UserService` that also handles authentication
- `utils.ts` with 2000 lines of unrelated functions
- `data` folder containing both models and migrations
- Example: `processUser()` that actually deletes users
5. **Circular or Tangled Dependencies** [category: `dependencies`]
- Service A imports from Service B which imports from Service A
- Shared types scattered across multiple packages
- Example: `auth` module depends on `user` module depends on `auth`
### Data Model Issues (Medium Confidence)
6. **Implicit Relationships** [category: `database-migrations`]
- Foreign keys exist in code but not in DB constraints
- Relationships documented nowhere
- Example: `order.userId` exists but no FK constraint, unclear if cascade deletes
7. **Overloaded Columns** [category: `schema`]
- Single column stores multiple types of data
- Status fields with 15+ possible values
- JSON blobs that should be normalized
- Example: `metadata` JSON column used for 8 different purposes
8. **Historical Cruft** [category: `legacy`]
- Deprecated columns still in schema
- Dead code paths still present
- Multiple versions of same logic
- Example: Both `v1_process()` and `process()` exist, unclear which to use
### Convention Drift (Lower Confidence)
9. **Style Guide Violations** [category: `code-organization`]
- Older code doesn't follow current patterns
- Different developers used different conventions
- Example: Half the codebase uses `async/await`, half uses `.then()`
10. **Missing Abstractions** [category: `code-organization`]
- Same boilerplate repeated across many files
- Copy-paste patterns that should be utilities
- Example: Same 20-line auth check in 15 different handlers
## Invocation Protocol
### Step 0: Check for Permanent Override
**FIRST**, check if user has permanently disabled this skill:
```bash
# If project has override skill, this skill is permanently disabled
if [ -f ".claude/skills/refactor-radar/SKILL.md" ]; then
# User has "shut up forever" - do nothing
exit 0
fi
```
### Step 0.5: Check User Preferences for Category Exclusions
- Check `~/.claude/CLAUDE.md` for excluded categories:
+ Check `~/.overdeck/context/global.md` for excluded categories:
```bash
- grep -A 20 "## AI Suggestion Preferences" ~/.claude/CLAUDE.md 2>/dev/null
+ grep -A 20 "## AI Suggestion Preferences" ~/.overdeck/context/global.md 2>/dev/null
```
Look for sections like:
```markdown
## AI Suggestion Preferences
### refactor-radar
skip: database-migrations, build-system, infrastructure
welcome: naming, code-organization
```
If the current trigger category is in the skip list, **do not prompt**.
### Step 1: Check Configuration
```bash
cat .overdeck/refactor-radar.json 2>/dev/null || echo "{}"
```
**Default configuration:**
```json
{
"enabled": true,
"mode": "normal",
"promptCooldownMinutes": 60,
"lastPromptTimestamp": null,
"proposalsCreated": 0,
"dismissedCount": 0,
"sessionDismissals": 0
}
```
**Modes:**
- `"aggressive"` - Prompt on every detected issue
- `"normal"` - High/medium confidence issues, respect cooldown
- `"minimal"` - Only obvious architectural problems
- `"silent"` - Log internally, never prompt
- `"disabled"` - Completely off
### Step 2: Respect Cooldowns
Skip prompting if:
- Mode is "disabled" or "silent"
- `sessionDismissals >= 2` (user said "not now" twice this session)
- Less than `promptCooldownMinutes` since last prompt
- Already proposed this exact issue before
### Step 3: Present to User
---
**Refactor Radar: Architectural Issue Detected** [category: {CATEGORY}]
I've noticed a systemic issue that's causing confusion:
**Issue:** [SPECIFIC PROBLEM]
**Evidence:**
- [CONCRETE EXAMPLE 1]
- [CONCRETE EXAMPLE 2]
**Impact:** This will likely cause repeated mistakes for me and other AI assistants working on this codebase.
**Would you like me to create a refactoring proposal?**
| Option | What happens |
|--------|--------------|
| **Yes, create issue** | I'll draft a detailed refactoring proposal as a GitHub/Linear issue |
| **Yes, but just notes** | I'll add notes to project documentation instead |
| **Not now** | Skip this time (I'll ask less often) |
- | **Skip this category** | Never suggest {CATEGORY} refactors (updates your ~/.claude/CLAUDE.md) |
+ | **Skip this category** | Never suggest {CATEGORY} refactors (updates your ~/.overdeck/context/global.md) |
| **Not important** | Don't track this issue (I may notice similar issues later) |
| **Too frequent** | Switch to minimal mode |
| **Stop asking** | Silent mode - log but don't prompt |
| **Shut up forever** | Permanently disable for this project |
---
### Step 4: Handle Responses
**"Yes, create issue":**
Create issue with template:
```markdown
## Refactoring Proposal: [TITLE]
### Problem
[Description of the architectural issue]
### Evidence
- [Specific examples found in codebase]
- [File paths and line numbers]
### Impact
- AI assistants repeatedly make mistakes due to this
- New developers likely face same confusion
- Increases maintenance burden
### Proposed Solution
[Concrete refactoring steps]
### Migration Path
[How to incrementally fix without breaking things]
### Acceptance Criteria
- [ ] [Specific measurable outcomes]
---
*Generated by Refactor Radar - AI-detected architectural improvement opportunity*
```
**"Skip this category":**
- 1. Update `~/.claude/CLAUDE.md` to add category to skip list
- 2. Acknowledge: "Got it - I won't suggest {CATEGORY} refactors anymore. You can edit ~/.claude/CLAUDE.md to change this."
+ 1. Update `~/.overdeck/context/global.md` to add category to skip list
+ 2. Acknowledge: "Got it - I won't suggest {CATEGORY} refactors anymore. You can edit ~/.overdeck/context/global.md to change this."
**"Shut up forever":**
Create override skill to permanently disable:
```bash
mkdir -p .claude/skills/refactor-radar
cat > .claude/skills/refactor-radar/SKILL.md << 'EOF'
---
name: refactor-radar
description: disabled-override-xK9mQ2
---
Disabled by user preference.
EOF
```
Acknowledge: "Refactor Radar permanently disabled for this project. Delete `.claude/skills/refactor-radar/` to re-enable."
### Step 5: Update Configuration
```bash
mkdir -p .overdeck
cat > .overdeck/refactor-radar.json << 'EOF'
{
"enabled": true,
"mode": "normal",
"promptCooldownMinutes": 60,
"lastPromptTimestamp": "2024-01-15T10:30:00Z",
"proposalsCreated": 2,
"dismissedCount": 1,
"sessionDismissals": 0,
"knownIssues": ["inconsistent-naming-user-account"]
}
EOF
```
- ## User Preferences in ~/.claude/CLAUDE.md
+ ## User Preferences in ~/.overdeck/context/global.md
- Users can exclude specific categories globally by adding to their personal `~/.claude/CLAUDE.md`:
+ Users can exclude specific categories globally by adding to their personal `~/.overdeck/context/global.md`:
```markdown
## AI Suggestion Preferences
### knowledge-capture
skip: database, authentication
### refactor-radar
skip: database-migrations, build-system, infrastructure
welcome: naming, code-organization, testing
```
### Available Categories
| Category | What it covers |
|----------|----------------|
| `naming` | Inconsistent naming, ambiguous names |
| `schema` | ORM/DB mismatches, overloaded columns, type mismatches |
| `patterns` | Inconsistent architectural patterns, mixed approaches |
| `dependencies` | Circular deps, tangled imports |
| `database-migrations` | FK constraints, schema changes, data integrity |
| `legacy` | Dead code, deprecated paths, cruft |
| `code-organization` | Missing abstractions, repeated boilerplate |
| `build-system` | Build tool inconsistencies, config issues |
| `infrastructure` | CI/CD, deployment, cloud config |
| `testing` | Test framework inconsistencies, coverage gaps |
| `authentication` | Auth flow issues, security patterns |
### Why Skip Categories?
**Database migrations:** "Schema changes require DBA approval and a formal change management process. AI suggestions here just create noise."
**Build system:** "Our build is ancient but stable. Touching it requires a dedicated sprint with full QA. Not happening anytime soon."
**Infrastructure:** "Platform team owns this. I'm a feature developer - infra proposals go nowhere."
**Legacy:** "We know there's legacy code. We have a 3-year modernization roadmap. Random cleanup PRs aren't helpful."
**Authentication:** "Security-critical code has strict review requirements. We don't want AI-generated proposals here."
### Why Welcome Categories?
**Naming:** "Naming consistency is low-risk and high-value. Always happy to fix these."
**Code organization:** "Refactoring utils and extracting abstractions is exactly what we need help with."
**Testing:** "Test improvements are always welcome - low risk, high value."
### Updating Preferences
To add a category exclusion:
```bash
# AI will add this section if it doesn't exist, or append to existing
- cat >> ~/.claude/CLAUDE.md << 'EOF'
+ cat >> ~/.overdeck/context/global.md << 'EOF'
## AI Suggestion Preferences
### refactor-radar
skip: database-migrations, infrastructure
welcome: naming, code-organization
EOF
```
To modify:
```bash
# Edit directly
- nano ~/.claude/CLAUDE.md
+ nano ~/.overdeck/context/global.md
```
To remove all exclusions:
```bash
# Remove the AI Suggestion Preferences section
- sed -i '/## AI Suggestion Preferences/,/^## /d' ~/.claude/CLAUDE.md
+ sed -i '/## AI Suggestion Preferences/,/^## /d' ~/.overdeck/context/global.md
```
## User Commands (Escalating Silence)
Users can control this skill via natural language, from gentle to nuclear:
| Command | Effect | Scope | Reversible? |
|---------|--------|-------|-------------|
| "Not now" / "Skip" | Skip this prompt | This session | Yes (automatic) |
| "Skip database migration suggestions" | Add to skip list | All projects | Yes (edit CLAUDE.md) |
| "I like naming suggestions" | Add to welcome list | All projects | Yes (edit CLAUDE.md) |
| "Refactor radar is too frequent" | Minimal mode | This project | Yes |
| "Stop suggesting refactors" | Silent mode | This project | Yes |
| "Disable refactor radar" | Completely off | This project | Yes |
| "Never suggest refactors again" | Create override | This project | Yes (delete file) |
**To re-enable after "shut up forever":**
```bash
rm -rf .claude/skills/refactor-radar/
```
## Example Proposals
### Example 1: Naming Inconsistency
**Detected:** Same entity called `user`, `account`, `member` across codebase
**Proposal:**
```markdown
## Refactoring Proposal: Standardize User Entity Naming
### Problem
The "user" concept has inconsistent naming across layers:
- Database: `accounts` table
- Backend models: `User` class
- API responses: `member` object
- Frontend state: `currentAccount`
### Evidence
- `src/models/User.ts` maps to `accounts` table
- `GET /api/members/:id` returns user data
- Frontend calls it `useAccount()` hook
### Proposed Solution
1. Standardize on `User` everywhere
2. Create type aliases during migration: `type Account = User`
3. Update API endpoints with deprecation period
4. Rename frontend hooks/state
### Migration Path
1. Add aliases (non-breaking)
2. Update new code to use `User`
3. Migrate existing code incrementally
4. Remove aliases after full migration
```
### Example 2: Mixed Async Patterns
**Detected:** Codebase mixes callbacks, promises, and async/await
**Proposal:**
```markdown
## Refactoring Proposal: Standardize on async/await
### Problem
Three different async patterns in use:
- Older services use callbacks
- Middle-era code uses `.then()` chains
- Newer code uses async/await
### Evidence
- `src/services/legacy/email.js`: callback-based
- `src/services/payment.ts`: Promise chains
- `src/services/user.ts`: async/await
### Impact
- AI assistants inconsistently apply patterns
- Error handling differs between approaches
- Code review burden increased
### Proposed Solution
Standardize on async/await with these utilities:
- `promisify()` wrapper for callback APIs
- ESLint rule to enforce async/await
- Gradual migration of existing code
### Migration Path
1. Add ESLint rule (warn only)
2. Migrate one service at a time
3. Upgrade to error after 80% migrated
```
### Example 3: Implicit Relationships
**Detected:** Foreign keys in code but not enforced in DB
**Proposal:**
```markdown
## Refactoring Proposal: Add Missing Foreign Key Constraints
### Problem
Relationships exist in application code but lack DB constraints:
- `orders.userId` references `users.id` but no FK
- `comments.postId` references `posts.id` but no FK
- Orphaned records exist in production
### Evidence
- `prisma/schema.prisma` defines relations
- `migrations/` shows no FK constraints
- Query: `SELECT COUNT(*) FROM orders WHERE userId NOT IN (SELECT id FROM users)` returns 47
### Impact
- Data integrity issues
- AI assumes cascading behavior that doesn't exist
- Silent failures on deletions
### Proposed Solution
1. Add FK constraints with migration
2. Clean up orphaned data first
3. Add ON DELETE behavior (CASCADE or SET NULL)
### Migration Path
1. Identify all orphaned records
2. Create cleanup migration
3. Add FK constraints
4. Update application code to handle constraint errors
```
## File Locations
| File | Purpose |
|------|---------|
- | `~/.claude/CLAUDE.md` | User preferences (category exclusions/welcomes) |
+ | `~/.overdeck/context/global.md` | User preferences (category exclusions/welcomes) |
| `.overdeck/refactor-radar.json` | Per-project configuration |
| `.claude/skills/refactor-radar/SKILL.md` | Override to permanently disable |
## Integration
Works with:
- - **knowledge-capture**: If same issue triggers both, prefer refactor-radar (systemic fix > workaround). Both skills share the same category exclusion system in ~/.claude/CLAUDE.md
+ - **knowledge-capture**: If same issue triggers both, prefer refactor-radar (systemic fix > workaround). Both skills share the same category exclusion system in ~/.overdeck/context/global.md
- **pan-skill-creator**: Can convert proposals into project-specific guidance
- Issue trackers: Creates issues in configured tracker (Linear, GitHub, GitLab)
## Override Skill Format
The override skill is intentionally minimal to save context:
```yaml
---
name: refactor-radar
description: disabled-override-xK9mQ2
---
Disabled by user preference.
```
The obscure description (`disabled-override-xK9mQ2`) ensures it never triggers on any user input. The body is minimal (4 words) to minimize context usage.