---
name: harness-entropy-cleaner
description: >
  Detect and fix codebase entropy including drift, dead code, and pattern violations. Use when running cleanup, detecting dead code, or fixing pattern violations.
tools: Bash, Read, Write, Edit, Glob, Grep
---

<!-- Generated by harness generate-agent-definitions. Do not edit. -->

## Role

Run scheduled cleanup, detect documentation drift, fix pattern violations

## Skills

- cleanup-dead-code
- detect-doc-drift
- harness-hotspot-detector
- harness-impact-analysis

## Steps

1. Run `harness cleanup` (always)
2. Run `harness fix-drift` (always)
3. Run `harness scan` (always)

## Methodology

# Cleanup Dead Code

> Entropy analysis and safe cleanup. Find unused exports, dead files, and pattern violations — then remove them without breaking anything.

## When to Use

- After a major refactoring or feature removal
- When the codebase feels "heavy" — too many files, unclear what is used
- As a periodic hygiene task (monthly or per-quarter)
- When `on_entropy_check` triggers fire
- After deleting a feature flag and its associated code paths
- When `harness cleanup` reports growing entropy in the project health dashboard
- NOT during active feature development — dead code cleanup is a separate, focused task
- NOT when tests are failing — fix tests first, then clean up
- NOT under time pressure — dead code removal requires careful verification

## Process

### Phase 1: Analyze — Run Entropy Report

1. **Run `harness cleanup`** to generate a full entropy report. This analyzes:
   - **Dead exports** — functions, classes, and constants that are exported but never imported anywhere
   - **Unused files** — files that are not imported by any other file in the project
   - **Pattern violations** — code that violates established project patterns (e.g., a service file without a corresponding test file)
   - **Orphaned dependencies** — npm packages listed in package.json but never imported

2. **Run `harness cleanup --type dead-code --json`** for machine-readable output focused specifically on unused code.

3. **Check for stale constraints.** Run `detect_stale_constraints` to identify architectural constraints referencing removed code that should also be cleaned up.

4. **Review the report summary.** Note the total count and distribution. A few dead exports are normal; dozens suggest accumulated entropy from incomplete refactorings.

### Graph-Enhanced Context (when available)

When a knowledge graph exists at `.harness/graph/`, use graph queries for faster, more accurate dead code detection:

- `query_graph` — perform graph reachability analysis from entry point nodes to identify truly unreachable code
- `get_relationships` — distinguish dynamic imports from genuinely unused code by checking edge types

Graph reachability reduces false positives compared to static analysis alone, since it traces the full transitive import graph including re-exports. Fall back to file-based commands if no graph is available.

### Phase 2: Categorize — Safe vs. Needs Review

**Safe to auto-fix (remove without further analysis):**

- Exports that are not imported anywhere AND not referenced in any config file
- Files that are not imported anywhere AND have no side effects (no top-level execution)
- Dead exports (non-public, zero importers) -- remove `export` keyword or delete entirely if zero internal callers
- Commented-out code blocks -- delete commented block (dead by definition, code is in git history)
- Orphaned npm dependencies -- remove from package.json (probably safe; needs install+test verification)
- Unused local variables and imports within a file (linter can catch these)

**Needs human review before removal:**

- Exports that APPEAR unused but might be consumed dynamically (see "What NOT to Delete" below)
- Files that appear unused but are entry points (CLI scripts, test fixtures, config files)
- Code that is only used in specific build configurations or environments
- Exports from a public package — external consumers may depend on them

### Phase 3: Apply Safe Fixes

For each item categorized as safe:

1. **Remove the dead code.** Delete the export, function, file, or import.

2. **Run `harness fix-drift`** to update any documentation references that pointed to the deleted code.

3. **Run the full test suite.** All tests must pass. If any test fails:
   - **STOP.** The code was not actually dead — something depends on it.
   - **Undo the deletion immediately.**
   - **Reclassify** the item as "needs human review" and investigate the hidden dependency.

4. **Run `harness validate` and `harness check-deps`.** Both must pass.

5. **Commit the cleanup.** Group related removals into logical commits (e.g., "remove unused shipping utilities" not "delete dead code").

**New fix types:**

- **Dead exports (non-public):** Use `detect_entropy` with `autoFix: true, fixTypes: ['dead-exports']`. The tool removes the `export` keyword. If the function/class has zero internal callers too, delete the entire declaration.
- **Commented-out code:** Use `detect_entropy` with `autoFix: true, fixTypes: ['commented-code']`. The tool deletes commented-out code blocks. This is cosmetic and only needs lint verification.
- **Orphaned dependencies:** Use `detect_entropy` with `autoFix: true, fixTypes: ['orphaned-deps']`. The tool removes the dep from package.json. **Must run `pnpm install && pnpm test` after** to verify nothing breaks.

### Phase 3.5: Convergence Loop (Standalone)

When running standalone (not through the orchestrator), apply a single-concern convergence loop:

1. **Re-run detection.** After applying all safe fixes, run `harness cleanup --type dead-code` again.
2. **Check if issue count decreased.** Compare the new count to the previous count.
3. **If decreased: loop.** New dead code may have been exposed by the fixes (e.g., removing a dead export made a file fully unused). Go back to Phase 2 (Categorize) with the new report.
4. **If unchanged: stop.** No more cascading fixes are possible. Proceed to Phase 4 (Report).
5. **Maximum iterations: 5.** To prevent infinite loops, stop after 5 convergence cycles regardless.

**Why convergence matters:** Removing dead code can create more dead code. For example:

- Removing a dead export may make all remaining exports in a file dead, making the file itself dead.
- Removing a dead file removes its imports, which may make other files' exports dead.
- Removing an orphaned dep may cause lint warnings that reveal unused imports.

### Phase 4: Report Remaining Items

### Graph Refresh

If a knowledge graph exists at `.harness/graph/`, refresh it after code changes to keep graph queries accurate:

```
harness scan [path]
```

Dead code removal changes graph topology — skipping this step means subsequent graph queries (impact analysis, dependency health, test advisor) may return stale results.

For items that need human review, report:

1. **What it is** — file path, export name, what it does
2. **Why it appears dead** — no static imports found
3. **Why it might not be dead** — dynamic import patterns, external consumers, test utilities
4. **Recommended action** — delete with confidence, delete with caution, or keep

## What NOT to Delete

These patterns make code APPEAR dead when it is actually in use:

### Dynamically imported modules

```typescript
// This import won't show up in static analysis
const module = await import(`./plugins/${pluginName}`);
```

Files in a `plugins/` directory may appear unused but are loaded dynamically at runtime. Check for `import()` calls, `require()` with variables, and glob-based loading patterns.

### Test utilities and fixtures

```typescript
// test-helpers.ts — only imported by test files
export function createMockUser() { ... }
```

Test utility files may appear unused if the analysis excludes test files. Verify that `harness cleanup` includes test files in its import graph.

### Type-only exports

```typescript
// Only used as a type, never as a value
export interface UserConfig { ... }
```

Some analysis tools miss type-only imports (`import type { UserConfig }`). Verify before deleting any exported interface or type alias.

### Package entry points

```typescript
// index.ts — re-exports for external consumers
export { createClient } from './client';
```

The entry point of a package re-exports things for external consumers. These exports may have zero internal imports but are the public API.

### Side-effect files

```typescript
// polyfills.ts — imported for side effects, not for exports
import './polyfills';
```

Some files are imported for their side effects (polyfills, global registrations, CSS). They have no exports but are not dead.

### Environment-specific code

```typescript
// Only used when FEATURE_FLAG_X is enabled
if (process.env.FEATURE_FLAG_X) {
  const handler = require('./experimental-handler');
}
```

Code behind feature flags or environment checks may appear dead in the default configuration.

## Harness Integration

- **`harness cleanup`** — Full entropy analysis. Reports dead exports, unused files, pattern violations, and orphaned dependencies.
- **`harness cleanup --type dead-code`** — Focused analysis on unused code specifically.
- **`harness cleanup --type dead-code --json`** — Machine-readable output for automation.
- **`harness fix-drift`** — Update documentation after removing dead code. Ensures deleted items are not still referenced in docs.
- **`harness validate`** — Run after cleanup to verify project structure remains valid.
- **`harness check-deps`** — Run after cleanup to verify no dependency violations were introduced.

## Success Criteria

- `harness cleanup` reports zero dead exports and zero unused files (or all remaining items are documented as intentional)
- All tests pass after every deletion
- `harness validate` and `harness check-deps` pass after cleanup
- Documentation references to deleted code are updated or removed
- No dynamically-imported, type-only, or side-effect code was accidentally deleted
- Each cleanup commit is atomic and has a descriptive message explaining what was removed and why

## Rationalizations to Reject

These are common rationalizations that sound reasonable but lead to incorrect results. When you catch yourself thinking any of these, stop and follow the documented process instead.

| Rationalization                                                                                        | Why It Is Wrong                                                                                                                                                 |
| ------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "This export has zero static imports, so it is definitely dead and safe to remove"                     | Zero static imports does not mean zero consumers. Dynamic imports, type-only imports, side-effect imports, and package entry points all create false positives. |
| "I removed the dead code and the tests pass, so I do not need to run harness validate and check-deps"  | Both harness validate and harness check-deps must pass after every cleanup. Dead code removal can introduce dependency violations.                              |
| "The convergence loop found new dead code after my fixes, but it is probably just noise from the tool" | Removing dead code creates more dead code. The convergence loop exists to catch these cascades. If the issue count decreased, loop back.                        |
| "The entropy report has 60 items but I can clean them all up in one pass to be thorough"               | When the report is very large (>50 items), pick the highest-confidence dead code first. Attempting everything at once risks compound errors.                    |

## Examples

### Example: Removing unused utility functions

**Entropy report:**

```
DEAD EXPORT: src/utils/string-helpers.ts
  - capitalizeFirst() — 0 imports found
  - truncateWithEllipsis() — 0 imports found
  - slugify() — 3 imports found (ACTIVE, not dead)
```

**Action:** Remove `capitalizeFirst` and `truncateWithEllipsis` from the file. Keep `slugify`. Run tests — all pass. Commit: "remove unused capitalizeFirst and truncateWithEllipsis from string-helpers"

### Example: Detecting a false positive

**Entropy report:**

```
UNUSED FILE: src/plugins/markdown-renderer.ts
  - 0 static imports found
  - File contains: export default class MarkdownRenderer
```

**Investigation:** Check for dynamic imports:

```typescript
// src/plugins/index.ts
const renderer = await import(`./${format}-renderer`);
```

**Result:** False positive. The file is loaded dynamically based on the `format` variable. Mark as intentional and add a comment in the file explaining the dynamic loading pattern.

### Example: Orphaned npm dependency

**Entropy report:**

```
ORPHANED DEPENDENCY: moment (package.json)
  - 0 imports of 'moment' found in src/
  - Last imported in commit abc123 (removed 3 months ago)
```

**Action:** Remove `moment` from package.json dependencies. Run `npm install` to update lockfile. Run tests — all pass. Commit: "remove unused moment dependency"

## Escalation

- **When removing code causes unexpected test failures:** The code has a hidden dependency. Undo the deletion, investigate the dependency chain, and document the finding. The code is not dead — it is just hard to trace.
- **When the entropy report is very large (>50 items):** Do not attempt to clean everything at once. Pick the highest-confidence dead code (files with zero imports, no dynamic patterns) and clean those first. Schedule the rest across multiple sessions.
- **When you are unsure if an export is used externally:** Check if the code is in a published package. If so, removing an export is a breaking change. Deprecate first, then remove in a major version.
- **When dead code is tangled with live code in the same file:** Extract the live code first (using harness-refactoring), then delete the remaining dead code. Do not try to surgically remove dead code from a complex file in one step.

---

# Detect Doc Drift

> Detect documentation that has drifted from code. Find stale docs before they mislead developers and AI agents.

## When to Use

- After completing a feature, bug fix, or refactoring
- During code review — check if the changed files have associated docs that need updating
- As a periodic hygiene check (weekly or per-sprint)
- When `on_post_feature` or `on_doc_check` triggers fire
- When onboarding reveals confusion caused by outdated documentation
- NOT during active development — wait until the code is stable before checking docs
- NOT for writing new documentation from scratch (use align-documentation instead)

## Process

### Phase 1: Scan — Run Drift Detection

1. **Run `harness check-docs`** to identify all documentation issues. Capture the full output.

2. **Run `harness cleanup --type drift`** for a deeper analysis that cross-references code changes against documentation references.

3. **Check for stale constraints.** Run `detect_stale_constraints` alongside drift detection to find architectural constraints that no longer match the codebase.

4. **Optionally, run `git diff` against a baseline** (last release, last sprint, etc.) to identify which code files changed. This helps prioritize — docs for recently changed files are most likely to be drifted.

### Graph-Enhanced Context (when available)

When a knowledge graph exists at `.harness/graph/`, use graph queries for faster, more accurate drift detection:

- `query_graph` — find `documents` edges where the target code node has changed since the doc node was last updated

When a graph is available, drift is simply stale edges: doc-to-code edges where the code side has been modified more recently than the doc side. This replaces regex pattern matching and catches semantic drift that text search misses. Fall back to file-based commands if no graph is available.

### Pipeline Context (when orchestrated)

When invoked by `harness-docs-pipeline`, check for a `pipeline` field in `.harness/handoff.json`:

- If `pipeline` field exists: read `DocPipelineContext` from it
  - Use `pipeline.exclusions` to skip findings that were already addressed in a previous phase
  - Write `DriftFinding[]` results back to `pipeline.driftFindings` in handoff.json
  - This enables the orchestrator to track findings across phases and avoid double-counting
- If `pipeline` field does not exist: behave exactly as today (standalone mode)

No changes to the skill's interface or output format — the pipeline field is purely additive.

### Phase 2: Identify — Classify Drift Types

Categorize each finding into one of these drift types:

**Renamed but not updated:**
A function, class, variable, or file was renamed in code, but documentation still references the old name. This is the most common type of drift.

- Example: `calculateShipping()` was renamed to `computeShippingCost()`, but AGENTS.md and three inline comments still say `calculateShipping`.

**New code with no docs:**
A new module, function, or API was added but no documentation entry exists. This is not "drift" in the strict sense but a gap that grows into drift over time.

- Example: `src/services/notification-service.ts` was added two sprints ago. It has 5 public exports. No AGENTS.md section, no doc page, no inline doc comments beyond basic JSDoc.

**Deleted code still referenced:**
A file, function, or feature was removed, but documentation still describes it as if it exists. This actively misleads readers.

- Example: `src/utils/legacy-parser.ts` was deleted. The architecture doc still includes it in the data flow diagram. AGENTS.md still warns about its quirks.

**Changed behavior not reflected:**
A function's signature, return type, error handling, or side effects changed, but the documentation describes the old behavior.

- Example: `createUser()` now throws `ValidationError` instead of returning `null` on invalid input. The API docs still say "returns null if validation fails."

**Moved code with stale paths:**
A file or module was moved to a different directory, but documentation references the old path.

- Example: `src/helpers/format.ts` was moved to `src/utils/format.ts`. Three doc files and AGENTS.md reference the old path.

### Phase 3: Prioritize — Rank by Impact

Not all drift is equally harmful. Prioritize fixes:

**Critical (fix immediately):**

- Public API documentation that describes wrong behavior — external consumers will write broken code
- AGENTS.md sections that reference deleted files — AI agents will hallucinate about non-existent code
- README getting-started guides with wrong commands — new developers cannot onboard

**High (fix before next release):**

- Internal API docs with wrong signatures — developers waste time debugging
- Architecture docs with stale diagrams — wrong mental models lead to wrong decisions
- Frequently accessed docs with broken links — high-traffic pages with dead ends

**Medium (fix in next sprint):**

- Internal docs for stable code — low change rate means low confusion rate
- Comments in rarely modified files — few people read them
- Edge case documentation — affects few users

**Low (fix when convenient):**

- Stylistic inconsistencies in docs (capitalization, formatting)
- Redundant documentation that says the same thing in multiple places
- Historical notes that are outdated but clearly marked as historical

### Phase 4: Report — Generate Actionable Output

For each drift finding, provide:

1. **File and line number** of the drifted documentation
2. **The specific stale content** (quote the exact text that is wrong)
3. **What changed in code** (the commit, file, and nature of the change)
4. **Suggested fix** (the replacement text or action needed)
5. **Priority tier** (Critical / High / Medium / Low)

Group findings by documentation file so that fixes can be applied file-by-file.

## Harness Integration

- **`harness check-docs`** — Primary tool. Scans all documentation files for broken references, stale paths, and missing entries.
- **`harness cleanup --type drift`** — Deeper analysis that cross-references git history with documentation references to detect semantic drift.
- **`harness cleanup --type drift --json`** — Machine-readable output for automated pipelines.
- **`harness fix-drift`** — Auto-fix simple drift issues after review (use align-documentation skill for applying fixes).

## Success Criteria

- `harness check-docs` reports zero errors
- All file paths referenced in documentation resolve to existing files
- All function/class names referenced in documentation match current code
- All API documentation matches current function signatures and behavior
- No documentation references deleted files, functions, or features
- Drift findings are prioritized and assigned to the appropriate fix cycle

## Rationalizations to Reject

| Rationalization                                                           | Why It Is Wrong                                                                                                                      |
| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| "The docs are close enough -- a renamed function is obvious from context" | Renamed references in AGENTS.md cause AI agents to hallucinate about non-existent code. Precision matters.                           |
| "We only changed internal code, so the docs do not need checking"         | Internal API docs with wrong signatures waste developer debugging time. Changed-behavior-not-reflected drift is High priority.       |
| "There are too many findings to deal with right now, so skip the scan"    | The escalation protocol exists for this case: focus on Critical and High items, create a tracking issue for the rest.                |
| "We can rely on code review to catch stale docs"                          | Code reviewers focus on code correctness, not documentation cross-references. harness check-docs catches what humans routinely miss. |

## Examples

### Example: Renamed function detected

**Drift finding:**

```
DRIFT: Renamed reference detected
  Doc: AGENTS.md:47
  Stale text: "Use `calculateShipping()` to compute shipping costs"
  Code change: calculateShipping renamed to computeShippingCost (commit a1b2c3d)
  File: src/services/shipping.ts:24
  Priority: High
  Suggested fix: Replace `calculateShipping()` with `computeShippingCost()`
```

### Example: Deleted file still documented

**Drift finding:**

```
DRIFT: Reference to deleted file
  Doc: docs/architecture.md:112
  Stale text: "The legacy parser (src/utils/legacy-parser.ts) handles XML input"
  Code change: File deleted in commit d4e5f6g, functionality merged into unified-parser.ts
  Priority: Critical
  Suggested fix: Update section to reference unified-parser.ts, remove legacy parser description
```

### Example: New module with no documentation

**Drift finding:**

```
GAP: Undocumented module
  File: src/services/notification-service.ts
  Created: commit h7i8j9k (3 weeks ago)
  Public exports: NotificationService, NotificationType, sendNotification
  Imported by: 4 modules
  Documentation references: 0
  Priority: High
  Suggested fix: Add AGENTS.md section describing purpose, constraints, and public API
```

## Escalation

- **When drift is extensive (>30 findings):** Do not try to fix everything. Focus on Critical and High priority items. Create a tracking issue for the remaining items and schedule them across sprints.
- **When you cannot determine the correct replacement text:** The code change may have been complex. Check the commit message and PR description for context. If still unclear, flag the finding for the original author to resolve.
- **When documentation is in a format you cannot parse:** Some docs may be in wiki pages, Confluence, or other external systems. Report the finding with a link and flag it for manual review.
- **When drift reveals a deeper problem (code changed but nobody knew):** This suggests a process gap. Recommend adding `harness check-docs` to the CI pipeline or pre-merge hooks to catch drift at the source.

---

# Harness Hotspot Detector

> Identify modules that represent structural risk via co-change and churn analysis.

## When to Use

- Weekly scheduled analysis to track codebase risk
- Before major refactoring — find the riskiest areas
- When investigating why changes keep breaking unrelated features
- NOT for finding dead code (use cleanup-dead-code)
- NOT for checking architecture rules (use enforce-architecture)

## Prerequisites

A knowledge graph at `.harness/graph/` with git history enables full analysis. If no graph exists,
the skill uses static analysis fallbacks (see Graph Availability section).
Run `harness scan` to enable graph-enhanced analysis.

### Graph Availability

Before starting, check if `.harness/graph/graph.json` exists.

**If graph exists:** Use graph tools as primary strategy. (Staleness sensitivity: **Low** — never auto-refresh.
Git-based churn data in the graph remains useful even when slightly stale.)

**If graph exists and is fresh (or refreshed):** Use graph tools as primary strategy.

**If no graph exists:** Output "Running without graph (run `harness scan` to
enable full analysis)" and use fallback strategies for all subsequent steps.

## Process

### Phase 1: CO-CHANGE — Analyze Co-Change Patterns

Query the graph for `co_changes_with` edges (created by GitIngestor):

```
query_graph(rootNodeIds=[all file nodes], includeEdges=["co_changes_with"])
```

Identify file pairs that frequently change together:

- **Co-located pairs** (same directory): Normal — they share a concern.
- **Distant pairs** (different modules): Suspicious — may indicate hidden coupling.

Flag distant co-change pairs as potential hotspots.

### Phase 2: CHURN — Identify High-Churn Files

Query commit nodes to find files with the highest change frequency:

```
query_graph(rootNodeIds=[commit nodes], includeTypes=["commit", "file"], includeEdges=["co_changes_with"])
```

Rank files by:

- Total commit count touching the file
- Recent velocity (commits in last 30 days vs prior 30 days)
- Change size (total lines added + deleted)

High churn in shared utilities or core modules = high risk.

#### Fallback (without graph)

When no graph is available, git log provides nearly all the data needed (~90% completeness):

1. **Per-file churn**: `git log --format="%H" -- <file>` for each source file (use glob to enumerate). Count commits per file. Sort descending to rank by churn.
2. **Recent velocity**: `git log --since="30 days ago" --format="%H" -- <file>` vs `git log --since="60 days ago" --until="30 days ago" --format="%H" -- <file>` to compare recent vs prior 30-day windows.
3. **Co-change detection**: `git log --format="%H %n" --name-only` to build a map of which files changed together in the same commit. File pairs that appear together in >3 commits are co-change candidates.
4. **Distant co-change identification**: For co-change pairs, check if they share a parent directory (co-located = normal) or are in different modules (distant = suspicious).
5. **Complexity proxy**: Use line count (`wc -l`) as a rough proxy for complexity when graph complexity metrics are unavailable.
6. **Hidden dependency detection**: Cross-reference co-change pairs against import parsing (grep for import statements). Co-change pairs with no import relationship indicate hidden dependencies.

> Fallback completeness: ~90% — git log provides nearly all the data the graph stores for this use case.

### Phase 3: COUPLING — Detect Hidden Dependencies

Cross-reference co-change data with structural data:

1. **High logical coupling, low structural coupling**: Files that always change together but have no `imports` edge between them. This indicates a hidden dependency — changing one requires changing the other, but the code doesn't express this relationship.

2. **High structural coupling, low logical coupling**: Files with `imports` edges but that rarely change together. This may indicate over-coupling — the import exists but the relationship is weak.

Use `get_relationships` to check structural edges between co-change pairs.

### Phase 4: REPORT — Generate Ranked Hotspot Report

```
## Hotspot Analysis Report

### Risk Hotspots (ranked by risk score)

1. **src/services/billing.ts** — Risk: HIGH
   - Churn: 23 commits (last 30 days: 8)
   - Co-changes with: src/types/invoice.ts (distant, 15 co-changes)
   - Hidden dependency: no imports edge to invoice.ts
   - Recommendation: Extract shared billing types or add explicit dependency

2. **src/utils/helpers.ts** — Risk: HIGH
   - Churn: 45 commits (highest in codebase)
   - Co-changes with: 12 different files across 4 modules
   - Recommendation: Split into domain-specific utilities to reduce blast radius

3. **src/middleware/auth.ts** — Risk: MEDIUM
   - Churn: 15 commits
   - Co-changes with: src/routes/login.ts (co-located, expected)
   - No hidden dependencies detected

### Summary
- Total hotspots detected: 5
- High risk: 2
- Medium risk: 3
- Hidden dependencies: 1
```

## Harness Integration

- **`harness scan`** — Recommended before this skill for full graph-enhanced analysis. If graph is missing, skill uses git log fallbacks.
- **`harness validate`** — Run after acting on findings to verify project health.
- **Graph tools** — This skill uses `query_graph`, `get_impact`, and `get_relationships` MCP tools.

## Success Criteria

- Hotspots ranked by composite risk score (churn + coupling)
- Hidden dependencies identified (high co-change, no structural edge)
- Co-change patterns detected and classified (co-located vs distant)
- Report follows the structured output format
- All findings are backed by graph query evidence (with graph) or git log analysis (without graph)

## Rationalizations to Reject

These are common rationalizations that sound reasonable but lead to incorrect results. When you catch yourself thinking any of these, stop and follow the documented process instead.

| Rationalization                                                                                                          | Why It Is Wrong                                                                                                                                         |
| ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "High churn just means the file is actively developed, not that it is risky"                                             | High churn in shared utilities specifically equals high risk. A file with 45 commits that co-changes with 12 different files indicates hidden coupling. |
| "The co-change pair is between two files in different modules, but they probably just happen to change at the same time" | Distant co-change pairs are flagged as suspicious precisely because they indicate hidden coupling.                                                      |
| "No graph exists so the analysis will be too incomplete to be useful"                                                    | Git log provides ~90% of the data needed for hotspot detection. The fallback is the highest-completeness fallback across all graph-enhanced skills.     |

## Examples

### Example: Detecting Hotspots in a Growing Codebase

```
Input: Scheduled weekly analysis on project root

1. CO-CHANGE — query_graph for co_changes_with edges
               Found 4 distant co-change pairs
2. CHURN     — Ranked files by commit frequency
               billing.ts: 23 commits, helpers.ts: 45 commits
3. COUPLING  — Cross-referenced co-change vs imports edges
               billing.ts <-> invoice.ts: 15 co-changes, no imports edge
               (hidden dependency detected)
4. REPORT    — Ranked hotspots by risk score

Output:
  Hotspots: 5 total (2 high, 3 medium)
  Hidden dependencies: 1 (billing.ts <-> invoice.ts)
  Top recommendation: Extract shared billing types
```

## Gates

- **Graph preferred, fallback available.** If no graph exists, use git log for churn and co-change analysis. Do not stop — git log provides ~90% of the data needed.
- **Systematic analysis required.** Use graph `co_changes_with` edges when available; use `git log` commit analysis when not. Do not guess — parse actual git history.

## Escalation

- **When hidden dependencies found**: Recommend making the dependency explicit (add import) or extracting shared code.
- **When a single file has >30 commits**: Flag as critical hotspot requiring architectural attention.

---

# Harness Impact Analysis

> Graph-based impact analysis. Answers: "if I change X, what breaks?"

## When to Use

- Before merging a PR — understand the blast radius of changes
- When planning a refactoring — know what will be affected
- When a test fails — trace backwards to find what change caused it
- When `on_pr` triggers fire
- NOT for understanding code (use harness-onboarding or harness-code-review)
- NOT for finding dead code (use cleanup-dead-code)

## Prerequisites

A knowledge graph at `.harness/graph/` enables full analysis. If no graph exists,
the skill uses static analysis fallbacks (see Graph Availability section).
Run `harness scan` to enable graph-enhanced analysis.

### Graph Availability

Before starting, check if `.harness/graph/graph.json` exists.

**If graph exists:** Check staleness — compare `.harness/graph/metadata.json`
scanTimestamp against `git log -1 --format=%ct` (latest commit timestamp).
If graph is more than 2 commits behind (`git log --oneline <scanTimestamp>..HEAD | wc -l`),
run `harness scan` to refresh before proceeding. (Staleness sensitivity: **High**)

**If graph exists and is fresh (or refreshed):** Use graph tools as primary strategy.

**If no graph exists:** Output "Running without graph (run `harness scan` to
enable full analysis)" and use fallback strategies for all subsequent steps.

## Process

### Phase 1: IDENTIFY — Determine Changed Files

1. **From diff**: If a git diff is available, parse it to extract changed file paths.
2. **From input**: If file paths are provided directly, use those.
3. **From git**: If neither, use `git diff --name-only HEAD~1` to get recent changes.

### Phase 2: ANALYZE — Query Graph for Impact

Run `compute_blast_radius` on target files to simulate failure propagation and identify all downstream modules affected. Run `predict_failures` to forecast which architectural constraints are most at risk from the proposed changes.

For each changed file:

1. **Direct dependents**: Use `get_impact` MCP tool to find all files that import or call the changed file.

   ```
   get_impact(filePath="src/services/auth.ts")
   → tests: [auth.test.ts, integration.test.ts]
   → docs: [auth-guide.md]
   → code: [routes/login.ts, middleware/verify.ts, ...]
   ```

2. **Transitive dependents**: Use `query_graph` with depth 3 to find indirect consumers.

   ```
   query_graph(rootNodeIds=["file:src/services/auth.ts"], maxDepth=3, includeEdges=["imports", "calls"])
   ```

3. **Documentation impact**: Use `get_relationships` to find `documents` edges pointing to changed nodes.

4. **Test coverage**: Identify test files connected via `imports` edges. Flag changed files with no test coverage.

5. **Design token impact**: When the graph contains `DesignToken` nodes, use `query_graph` with `USES_TOKEN` edges to find components that consume changed tokens.

   ```
   query_graph(rootNodeIds=["designtoken:color.primary"], maxDepth=2, includeEdges=["uses_token"])
   → components: [Button.tsx, Card.tsx, Header.tsx, ...]
   ```

   If a changed file is `design-system/tokens.json`, identify ALL tokens that changed and trace each to its consuming components. This reveals the full design blast radius of a token change.

6. **Design constraint impact**: When the graph contains `DesignConstraint` nodes, check if changed code introduces new `VIOLATES_DESIGN` edges.

#### Fallback (without graph)

When no graph is available, use static analysis to approximate impact:

1. **Parse imports**: For each changed file, grep all source files for `import.*from.*<changed-file>` and `require.*<changed-file>` patterns to find direct dependents.
2. **Follow imports 2 levels deep**: For each direct dependent found, repeat the import grep to find second-level dependents. Stop at 2 levels (fallback cannot reliably trace deeper).
3. **Find test files by naming convention**: For each changed file `foo.ts`, search for:
   - `foo.test.ts`, `foo.spec.ts` (same directory and `__tests__/` directory)
   - `*.test.*` and `*.spec.*` files that import the changed file (from step 1)
4. **Find docs by path matching**: Grep `docs/` directory for references to the changed module name (filename without extension).
5. **Group results** the same as the graph version: tests, docs, code, other. Note the count of files found.

> Fallback completeness: ~70% — misses transitive deps beyond 2 levels.

### Phase 3: ASSESS — Risk Assessment and Report

1. **Impact score**: Calculate based on:
   - Number of direct dependents (weight: 3x)
   - Number of transitive dependents (weight: 1x)
   - Whether affected code includes entry points (weight: 5x)
   - Whether tests exist for the changed code (no tests = higher risk)
   - Whether design tokens are affected (weight: 2x — token changes cascade to all consumers)

2. **Risk tiers**:
   - **Critical** (score > 50): Changes affect entry points or >20 downstream files
   - **High** (score 20-50): Changes affect multiple modules or shared utilities
   - **Medium** (score 5-20): Changes affect a few files within the same module
   - **Low** (score < 5): Changes are isolated with minimal downstream impact

3. **Output report**:

   ```
   ## Impact Analysis Report

   ### Changed Files
   - src/services/auth.ts (modified)
   - src/types/user.ts (modified)

   ### Impact Summary
   - Direct dependents: 8 files
   - Transitive dependents: 23 files
   - Affected tests: 5 files
   - Affected docs: 2 files
   - Risk tier: HIGH

   ### Affected Tests (must run)
   1. tests/services/auth.test.ts (direct)
   2. tests/routes/login.test.ts (transitive)
   3. tests/integration/auth-flow.test.ts (transitive)

   ### Affected Documentation (may need update)
   1. docs/auth-guide.md → documents src/services/auth.ts
   2. docs/api-reference.md → documents src/types/user.ts

   ### Downstream Consumers
   1. src/routes/login.ts — imports auth.ts
   2. src/middleware/verify.ts — imports auth.ts
   3. src/routes/signup.ts — imports user.ts (transitive via auth.ts)

   ### Affected Design Tokens (when tokens change)
   1. color.primary → used by 12 components
   2. typography.body → used by 8 components
   ```

## Harness Integration

- **`harness scan`** — Recommended before this skill for full graph-enhanced analysis. If graph is missing, skill uses static analysis fallbacks.
- **`harness validate`** — Run after acting on findings to verify project health.
- **Graph tools** — This skill uses `query_graph`, `get_impact`, and `get_relationships` MCP tools.

## Success Criteria

- Impact report generated with a risk tier (Critical / High / Medium / Low)
- All affected test files listed with direct vs transitive classification
- All affected documentation files listed with relationship context
- Report follows the structured output format
- All findings are backed by graph query evidence (with graph) or systematic static analysis (without graph)

## Rationalizations to Reject

These are common rationalizations that sound reasonable but lead to incorrect results. When you catch yourself thinking any of these, stop and follow the documented process instead.

| Rationalization                                                                                    | Why It Is Wrong                                                                                                                          |
| -------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| "The change is small so the blast radius must be low -- I can skip the transitive dependent check" | Small changes to shared utilities can have outsized blast radius. A one-line change to auth.ts can affect 23 transitive dependents.      |
| "The graph is a few commits behind but it is close enough for this analysis"                       | If the graph is more than 2 commits behind, the skill requires a refresh before proceeding. Recent commits may have added new consumers. |
| "No graph exists so I cannot produce a useful impact analysis"                                     | The fallback strategy using import parsing and naming conventions achieves ~70% completeness. Missing the graph does not mean stopping.  |

## Examples

### Example: Analyzing a Change to auth.ts

```
Input: git diff shows src/services/auth.ts modified

1. IDENTIFY — Extract changed file: src/services/auth.ts
2. ANALYZE  — get_impact(filePath="src/services/auth.ts")
              query_graph(rootNodeIds=["file:src/services/auth.ts"], maxDepth=3)
              Results: 8 direct dependents, 23 transitive, 5 tests, 2 docs
3. ASSESS   — Impact score: 34 (High tier)
              - Entry points affected: no
              - Tests exist: yes (5 files)

Output:
  Risk tier: HIGH
  Must-run tests: auth.test.ts, login.test.ts, auth-flow.test.ts
  Docs to update: auth-guide.md, api-reference.md
  Downstream consumers: 8 files across 3 modules
```

## Gates

- **Graph preferred, fallback available.** If no graph exists, use fallback strategies (import parsing, naming conventions, path matching). Do not stop — produce the best analysis possible with available tools.
- **No risk assessment without data.** Use graph queries when available; use import parsing and naming conventions when not. If neither approach yields data, state what is missing.

## Escalation

- **When graph is stale**: If the graph's last scan timestamp is older than the most recent commit, warn that results may be incomplete and suggest re-scanning.
- **When impact is critical**: If risk tier is Critical, recommend a thorough code review and full test suite run before merging.
