---
name: harness-architecture-enforcer
description: >
  Validate architectural constraints and dependency rules. Use when checking layer boundaries, detecting circular dependencies, or verifying import direction compliance.
---

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

## Role

Enforce layer boundaries, detect circular dependencies, block forbidden imports

## Skills

- enforce-architecture
- check-mechanical-constraints
- harness-dependency-health

## Steps

1. Run `harness check-deps` (always)
2. Run `harness validate` (always)

## Methodology

# Enforce Architecture

> Validate architectural layer boundaries and detect dependency violations. No code may violate layer constraints — this is a hard gate, not a suggestion.

## When to Use

- Before approving any pull request or merge
- After writing new imports or module references
- When adding a new module or package to the project
- When `on_pre_commit` or `on_architecture_check` triggers fire
- After refactoring that moves code between layers or modules
- NOT when editing documentation, configuration, or non-code files
- NOT when the violation is intentional and requires a constraint update (escalate instead)

## Process

### Phase 1: Load Constraints

1. **Read `harness.config.json`** to understand the project's architectural constraints. The config defines:
   - **Layers** — ordered list of architectural layers (e.g., `ui -> service -> repository -> domain`)
   - **Dependency rules** — which layers may import from which (typically: layers may only import from layers below them)
   - **Forbidden imports** — specific import paths that are never allowed in certain contexts
   - **Boundary definitions** — which directories/packages belong to which layer

- **Design constraints** — when `design` config exists, also load design constraint rules:
  - Token compliance — components must reference design tokens, not hardcoded values
  - Accessibility compliance — color pairs must meet WCAG contrast ratios
  - Anti-pattern enforcement — project-specific anti-patterns from `design-system/DESIGN.md`
  - Platform binding — tokens must have appropriate platform bindings for enabled platforms

2. **Understand the layer model.** In a typical layered architecture:
   - Higher layers depend on lower layers (UI depends on Service, Service depends on Repository)
   - Lower layers NEVER depend on higher layers (Repository must not import from UI)
   - Same-layer imports may or may not be allowed depending on project config
   - Cross-cutting concerns (logging, config) have their own rules

### Graph-Enhanced Context (when available)

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

- `query_graph` — traverse `imports` edges against layer constraint nodes to find all violations in a single query
- `get_relationships` — find all code dependent on a violation target to show the full scope of impact

Graph queries show the complete violation scope (not just the first occurrence per file) and reveal transitive violations that single-file analysis misses. Fall back to file-based commands if no graph is available.

### Phase 2: Run Dependency Checks

1. **Run `harness check-deps`** to analyze all import statements against the constraint model. Capture the full JSON output.

1b. **Optionally run `harness check-arch`** for comprehensive architecture analysis beyond dependency checking. This covers circular dependencies, complexity, coupling, module size, and dependency depth in addition to layer violations.

2. **Parse the results.** Each violation includes:
   - The violating file and line number
   - The forbidden import target
   - The source layer and target layer
   - The specific rule being violated

### Phase 3: Analyze Violations

For each violation, determine:

1. **Which layers are involved.** Identify the source file's layer and the imported module's layer. Map them to the constraint model.

2. **What rule is violated.** Common violation types:
   - **Upward dependency** — a lower layer imports from a higher layer (e.g., repository importing from UI). This is the most serious type. It creates coupling that makes the lower layer untestable in isolation.
   - **Skip-layer dependency** — a layer reaches past its immediate neighbor (e.g., UI importing directly from Repository, bypassing Service). This breaks encapsulation and makes the middle layer pointless.
   - **Circular dependency** — two modules or layers depend on each other. This creates fragile coupling where changing either module risks breaking the other.
   - **Forbidden import** — a specific import that is explicitly banned (e.g., importing a database driver outside the repository layer). This prevents implementation details from leaking.
   - **Design constraint violation** — a component uses hardcoded values instead of design tokens, or violates a declared anti-pattern. Severity depends on `design.strictness` in config. These violations surface as DESIGN-xxx codes:
     - `DESIGN-001` [warn] — Hardcoded color/font/spacing instead of token reference
     - `DESIGN-002` [warn] — Value matches a project anti-pattern
     - `DESIGN-003` [error] — WCAG contrast ratio failure (error in strict mode)
     - `DESIGN-004` [info] — Missing platform binding for enabled platform

3. **Explain the impact.** For each violation, state:
   - WHY the constraint exists (what architectural property it protects)
   - WHAT would happen if the violation were allowed to persist
   - HOW it affects testability, maintainability, and changeability

### Phase 3.5: Apply Safe Architecture Fixes

Some architecture violations can be auto-fixed. Apply these before surfacing remaining violations.

**Import ordering violations:**

1. Identify files where imports are not ordered according to the project's layer convention.
2. Reorder imports: external packages first, then by layer (lowest to highest), then relative imports.
3. Verify with lint + typecheck. This is a safe, mechanical fix.

**Forbidden import replacement (with configured alternative):**

1. Check `harness.config.json` for `forbiddenImports` entries that include an `alternative` field.
2. For each violation where an alternative exists, replace the import path with the alternative.
3. Verify with typecheck + test. This is "probably safe" -- present as a diff for approval in interactive mode, apply silently in CI mode.

**Design token substitution (unambiguous mapping):**

1. When a hardcoded value has exactly one matching design token, replace the literal with the token reference.
2. Verify with typecheck + test.
3. If the mapping is ambiguous (multiple candidate tokens), surface to user.

**Never auto-fix these (always surface to user):**

- Upward dependencies
- Skip-layer dependencies
- Circular dependencies
- Forbidden imports without a configured alternative

### Phase 3.6: Convergence Loop (Standalone)

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

1. **Re-run detection.** After applying all safe/probably-safe fixes, run `harness check-deps` again.
2. **Check if violation count decreased.** Compare the new count to the previous count.
3. **If decreased: loop.** Fixing one violation can resolve others (e.g., replacing a forbidden import may eliminate a transitive skip-layer violation). Go back to Phase 2 with the new results.
4. **If unchanged: stop.** Proceed to Phase 4 (Guide Resolution) for remaining violations.
5. **Maximum iterations: 5.** To prevent infinite loops.

**Verification gate:** After each fix batch, run:

```
pnpm lint && pnpm tsc --noEmit && pnpm test
```

If any command fails, revert the batch and reclassify those findings as unsafe.

### Phase 4: Guide Resolution

For each violation, provide a specific fix:

- **Upward dependency:** Introduce an interface or abstraction in the lower layer. The higher layer implements it; the lower layer depends only on the abstraction. Alternatively, use dependency injection.
- **Skip-layer dependency:** Route the call through the intermediate layer. Add a method to the Service layer that delegates to the Repository, then have the UI call the Service.
- **Circular dependency:** Break the cycle by extracting shared types into a common module that both can depend on, or restructure so the dependency flows in one direction only.
- **Forbidden import:** Check `harness.config.json` for an `alternative` field. If present, this should have been auto-fixed in Phase 3.5. If not present, replace the forbidden import with the approved alternative or restructure the code.
- **Design constraint violation:** Replace hardcoded values with token references from `design-system/tokens.json`. For anti-pattern violations, consult `design-system/DESIGN.md` for the project's aesthetic intent and approved alternatives. For contrast failures, use `harness-accessibility` to find compliant color pairs.

## Common Violation Patterns

### Pattern: "I just need one thing from that layer"

A UI component imports a repository function directly because "it is just one query." Fix: add the query to the Service layer. The extra indirection is the architecture working correctly.

### Pattern: "Shared types across layers"

Two layers both need the same type definition. Fix: place shared types in the lowest layer that both depend on, or create a dedicated `types` or `shared` module at the bottom of the layer stack.

### Pattern: "Test utilities importing production code from wrong layer"

Test helpers import across layer boundaries for convenience. Fix: each layer's tests should only import from that layer and below. Test utilities should follow the same constraints as production code.

### Pattern: "Hardcoded colors in components"

A component uses `#3b82f6` directly instead of referencing `color.primary` from the design token system. Fix: import and reference the token. In Tailwind: use the token-mapped utility class. In CSS: use the custom property `var(--color-primary)`.

### Pattern: "Circular dependency through re-exports"

Module A re-exports from Module B, and Module B imports from Module A. The circular dependency is hidden by the re-export. Fix: identify the true dependency direction and remove the reverse path.

## Harness Integration

- **`harness check-deps`** — Primary tool. Analyzes all imports against the layer model defined in `harness.config.json`. Returns structured violation data including file, line, source layer, target layer, and rule violated.
- **`harness check-deps --json`** — Machine-readable output for automated pipelines. Use this when parsing results programmatically.
- **`harness validate`** — Includes dependency checking as part of full project validation. Use when you want a complete health check, not just architecture.
- **`harness-design-system`** — Provides the design token source of truth (`tokens.json`) that constraints validate against.
- **`harness-accessibility`** — Provides WCAG contrast validation used by DESIGN-003 constraints.
- **Design constraint category** — Controlled by `design.strictness` in `harness.config.json`. Design violations surface alongside architectural violations in the same report.
- **`harness check-arch`** — Architecture assertion framework. Runs all 7 metric collectors against baseline and thresholds. Use for comprehensive structural health checks beyond layer dependencies. Supports `--update-baseline` to capture current state and `--json` for machine-readable output.
- **`harness check-arch --module <path>`** — Scoped architecture check for a single module. Use when validating a specific subsystem.

## Success Criteria

- `harness check-deps` reports zero violations
- All imports flow downward through the layer stack (or follow explicitly configured exceptions)
- No circular dependencies exist between modules or layers
- No forbidden imports are present anywhere in the codebase
- Every new module is assigned to the correct layer in the config
- The layer model in `harness.config.json` accurately reflects the intended architecture

## Examples

### Example: Service layer importing from UI layer

**Violation from `harness check-deps`:**

```
VIOLATION: Upward dependency
  File: src/services/user-service.ts:12
  Import: import { UserForm } from '../components/UserForm'
  Source layer: service (level 2)
  Target layer: ui (level 3)
  Rule: service layer must not depend on ui layer
```

**Impact:** The UserService now depends on a React component. It cannot be used in a CLI tool, a background job, or tested without a DOM. The service layer should be framework-agnostic.

**Resolution:**

```typescript
// BEFORE (violating)
import { UserForm } from '../components/UserForm';
const data = UserForm.defaultValues; // using UI defaults in service

// AFTER (fixed)
// Define the defaults where they belong — in the service layer
const DEFAULT_USER_DATA: UserInput = { name: '', email: '' };
```

### Example: Circular dependency between modules

**Violation from `harness check-deps`:**

```
VIOLATION: Circular dependency detected
  Cycle: src/services/order-service.ts -> src/services/inventory-service.ts -> src/services/order-service.ts
  order-service imports checkStock from inventory-service
  inventory-service imports getOrderQuantity from order-service
```

**Resolution:** Extract the shared concern into a new module:

```typescript
// src/services/stock-calculator.ts (new, shared module)
export function calculateRequiredStock(quantity: number, reserved: number): number {
  return quantity - reserved;
}
```

Both services import from `stock-calculator` instead of from each other. The cycle is broken.

## Gates

These are hard stops. Architecture violations are not warnings — they are errors.

- **No code with layer violations may be approved or merged.** If `harness check-deps` reports violations, the code must be fixed before it proceeds.
- **No new modules without layer assignment.** Every new directory or package must be mapped to a layer in `harness.config.json` before code is written in it.
- **No "temporary" violations.** There is no TODO for architecture. Either the code respects the constraints or it does not ship.
- **No suppressing violations without team approval.** If a violation needs to be allowed, the constraint in `harness.config.json` must be explicitly updated with a comment explaining why.

## Evidence Requirements

When this skill makes claims about existing code, architecture, or behavior,
it MUST cite evidence using one of:

1. **File reference:** `file:line` format (e.g., `src/auth.ts:42`)
2. **Code pattern reference:** `file` with description (e.g., `src/utils/hash.ts` —
   "existing bcrypt wrapper")
3. **Test/command output:** Inline or referenced output from a test run or CLI command
4. **Session evidence:** Write to the `evidence` session section via `manage_state`

**Uncited claims:** Technical assertions without citations MUST be prefixed with
`[UNVERIFIED]`. Example: `[UNVERIFIED] The auth middleware supports refresh tokens`.

## Red Flags

### Universal

These apply to ALL skills. If you catch yourself doing any of these, STOP.

- **"I believe the codebase does X"** — Stop. Read the code and cite a file:line
  reference. Belief is not evidence.
- **"Let me recommend [pattern] for this"** without checking existing patterns — Stop.
  Search the codebase first. The project may already have a convention.
- **"While we're here, we should also [unrelated improvement]"** — Stop. Flag the idea
  but do not expand scope beyond the stated task.

### Domain-Specific

- **"Auto-fixing this import to use the correct layer"** without verifying the replacement module exists — Stop. Verify the target exists and exports the needed symbol before rewriting an import.
- **"This file is in a test directory, skipping violation"** — Stop. Test directories have architectural rules too. Check the constraint definition before assuming tests are exempt.
- **"Removing this circular dependency by moving the import"** without tracing downstream effects — Stop. Moving imports can break consumers. Trace the dependency chain first.
- **"This violation is from generated code, ignoring"** — Stop. Generated files can still violate architecture if the generator is misconfigured. Check the source template.

## Rationalizations to Reject

### Universal

These reasoning patterns sound plausible but lead to bad outcomes. Reject them.

- **"It's probably fine"** — "Probably" is not evidence. Verify before asserting.
- **"This is best practice"** — Best practice in what context? Cite the source and
  confirm it applies to this codebase.
- **"We can fix it later"** — If it is worth flagging, it is worth documenting now
  with a concrete follow-up plan.

### Domain-Specific

| Rationalization                                  | Reality                                                                                                                              |
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| "The violation is minor — just one import"       | One violation sets a precedent. Enforce the constraint or document an explicit exception with rationale.                             |
| "It works, so the architecture must be fine"     | Working code with bad architecture is technical debt with compound interest. Correct function does not excuse structural violations. |
| "This is a legacy module, different rules apply" | Legacy does not mean exempt. Either the constraint applies or it needs an explicit documented exception.                             |

## Escalation

- **When a violation seems impossible to fix within the current architecture:** The architecture may need to evolve. Escalate to the human with a clear explanation of the constraint, the use case, and why they conflict. Propose options: update the constraint, restructure the code, or add a new layer.
- **When `harness check-deps` reports false positives:** Verify the layer assignments in `harness.config.json` are correct. If a file is assigned to the wrong layer, fix the config. If the tool is genuinely wrong, report the issue.
- **When fixing one violation creates another:** This usually indicates a deeper structural issue. Step back and look at the dependency graph as a whole rather than fixing violations one at a time.
- **When the team wants to change the layer model:** This is a significant architectural decision. All existing code must be migrated to the new model. Plan this as a dedicated refactoring effort, not a side task.

---

# Check Mechanical Constraints

> Run all mechanical constraint checks: linter rules, boundary schemas, and forbidden imports. These are automated, enforceable rules — if it can be checked by a machine, it must be.

## When to Use

- Before every commit (ideally via pre-commit hook)
- Before submitting a pull request for review
- After any code generation or automated refactoring
- When `on_pre_commit` or `on_validate` triggers fire
- After resolving merge conflicts (constraints may have been silently violated)
- NOT as a substitute for code review — mechanical constraints catch structural issues, not logic errors
- NOT when only editing non-code files (docs, config) unless those files have their own schema constraints

## Process

### Phase 1: Run All Checks

1. **Run `harness validate`** to check project-wide constraints: file structure, naming conventions, required files, and configuration validity.

2. **Run `harness linter validate`** to check all linter rules: code style, import restrictions, forbidden patterns, and boundary schemas.

3. **Run `harness check-deps`** to check architectural layer boundaries. This is included here because dependency violations are mechanical — they can be detected purely from import statements and the constraint config.

4. **Capture all output.** Combine results from all three commands into a single violation list for triage.

### Phase 2: Categorize Violations by Severity

Organize violations into three tiers:

**Tier 1 — Errors (must fix before commit):**

- Forbidden imports (importing banned modules)
- Layer boundary violations (importing across architectural boundaries)
- Schema violations (config files that do not match required schema)
- Missing required files (every package must have index.ts, etc.)

**Tier 2 — Warnings (must fix before merge):**

- Naming convention violations (wrong casing, wrong prefix)
- Import ordering issues
- Unused exports detected by linter
- Documentation file references that do not resolve

**Tier 3 — Info (fix when convenient):**

- Style suggestions (formatting that does not affect behavior)
- Complexity warnings (functions exceeding thresholds)
- Minor inconsistencies with project conventions

### Phase 3: Auto-Fix Where Safe

Some violations can be fixed automatically without risk:

- **Import ordering** — reorder imports to match the configured convention. This never changes behavior.
- **Formatting** — apply the project's formatter (prettier, etc.). Pure whitespace and style changes.
- **Simple forbidden imports** — when a forbidden import has a known replacement (e.g., `import lodash` to `import lodash-es`), apply the substitution.
- **Missing trailing commas, semicolons** — mechanical formatting fixes.

**Rules for auto-fix:**

- ONLY auto-fix violations that cannot change runtime behavior
- Run the test suite after auto-fixing to confirm nothing broke
- Present the auto-fix diff to the user for awareness (do not silently change code)
- If unsure whether a fix is safe, do NOT auto-fix — report it for manual resolution

### Phase 4: Report Remaining Violations

For each violation that was not auto-fixed, report:

1. **File and line number** — exact location of the violation
2. **Rule name** — which constraint was violated
3. **What it protects against** — why this rule exists (see reference below)
4. **How to fix** — specific guidance for resolving this type of violation
5. **Severity tier** — whether it blocks commit, merge, or is informational

## What Each Constraint Type Protects Against

### Forbidden Imports

**Protects against:** Implementation detail leakage and unwanted coupling. When a library is forbidden in a layer, it is because using it there would create a dependency that makes the layer harder to test, replace, or maintain. Example: forbidding `fs` in the UI layer ensures UI code never directly accesses the filesystem.

### Layer Boundaries

**Protects against:** Architectural erosion. Without enforced boundaries, codebases gradually become a tangle where everything depends on everything. Layer boundaries ensure changes in one area do not ripple unpredictably through the whole system.

### Boundary Schemas

**Protects against:** Configuration drift and invalid state. When config files must match a schema, you catch invalid configurations at lint time rather than at runtime. This prevents deployment failures and hard-to-debug runtime errors.

### Naming Conventions

**Protects against:** Cognitive overhead and inconsistency. Consistent naming means developers (human and AI) can predict file locations, function names, and module structure without searching. It also ensures automated tools that rely on naming patterns continue to work.

### Required File Rules

**Protects against:** Incomplete modules. When every package must have an `index.ts` or every component must have a test file, you ensure that the project structure remains complete and navigable.

### Import Ordering

**Protects against:** Merge conflicts and readability issues. Consistent import ordering reduces git conflicts when multiple developers add imports to the same file. It also makes imports scannable at a glance.

## Harness Integration

- **`harness validate`** — Project-wide structural validation. Checks file structure, naming conventions, required files, and configuration schemas.
- **`harness validate --json`** — Machine-readable output for parsing and categorization.
- **`harness linter validate`** — Runs all configured linter rules. Checks code patterns, import restrictions, and style conventions.
- **`harness check-deps`** — Architectural boundary enforcement. Checks all imports against the layer model.
- **`harness check-deps --json`** — Machine-readable dependency check output.

## Success Criteria

- All three commands (`harness validate`, `harness linter validate`, `harness check-deps`) pass with zero errors
- All Tier 1 violations are resolved before any commit
- All Tier 2 violations are resolved before any merge to main
- Auto-fixed changes are verified by running the test suite
- No violations are suppressed without explicit team approval and a documented reason

## Rationalizations to Reject

| Rationalization                                                                       | Why It Is Wrong                                                                                                                         |
| ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| "This forbidden import is just for one utility function -- I will suppress it inline" | The gate says no suppressing rules without documentation. Undocumented suppressions accumulate and erode the constraint system.         |
| "The auto-fix looks right, so I do not need to re-run tests"                          | The gate says no auto-fix without test verification. Even import reordering can break code that depends on module initialization order. |
| "This is just a Tier 2 warning -- it can wait until after merge"                      | Tier 2 violations must be resolved before merge to main. Warnings that accumulate on main become the new baseline.                      |
| "The linter rule does not make sense for this project, so I will just disable it"     | Propose a config change with justification, do not disable the rule inline. Fix it at the configuration level.                          |

## Examples

### Example: Forbidden import detected

**Violation:**

```
ERROR [forbidden-import] src/components/Dashboard.tsx:3
  Import 'pg' is forbidden in layer 'ui'
  Rule: ui layer must not import database drivers
```

**What it protects against:** The UI layer importing a PostgreSQL driver means UI code could execute raw SQL queries, bypassing the service and repository layers entirely. This breaks testability (tests need a real database) and security (SQL injection risk from UI layer).

**Fix:** Remove the direct database call. Add the needed query to the appropriate repository, expose it through the service layer, and call the service from the UI component.

### Example: Auto-fixable import ordering

**Violation:**

```
WARNING [import-order] src/services/auth-service.ts:1-8
  Imports are not in the configured order
  Expected: builtin -> external -> internal -> relative
  Found: relative -> external -> builtin
```

**Auto-fix applied:**

```typescript
// BEFORE
import { hashPassword } from './utils';
import bcrypt from 'bcrypt';
import { createHash } from 'crypto';

// AFTER (auto-fixed)
import { createHash } from 'crypto';
import bcrypt from 'bcrypt';
import { hashPassword } from './utils';
```

Tests re-run: all passing. No behavioral change.

### Example: Schema violation in config

**Violation:**

```
ERROR [schema-violation] harness.config.json:24
  Property 'layers[2].allowedImports' must be an array of strings
  Found: number (42)
  Schema: harness-config-schema.json#/properties/layers/items/properties/allowedImports
```

**What it protects against:** An invalid config means `harness check-deps` will either crash or silently skip validation. The layer constraints would not be enforced, allowing violations to slip through undetected.

**Fix:** Correct the config value to be a valid string array: `"allowedImports": ["@shared/types", "@shared/utils"]`.

## Gates

These are hard stops. Mechanical constraints are non-negotiable.

- **No commits with Tier 1 violations.** Errors must be resolved before the code is committed. No exceptions.
- **No merges with Tier 2 violations.** Warnings must be resolved before merging to the main branch.
- **No suppressing rules without documentation.** If a rule must be disabled for a specific line or file, the suppression comment must explain WHY (not just disable the rule).
- **No auto-fix without test verification.** Every auto-fix must be followed by a test run to confirm no behavioral change.

## Escalation

- **When a rule seems wrong for the project:** Rules are configured in `harness.config.json` and linter configs. If a rule does not fit, propose a config change with justification. Do not disable the rule inline.
- **When a violation cannot be fixed without a larger refactor:** Document the violation, create a task for the refactor, and get team approval for a temporary inline suppression with a TODO linking to the task.
- **When auto-fix produces unexpected changes:** Undo the auto-fix, report the issue, and fix manually. Auto-fix tools are not infallible.
- **When multiple constraints conflict:** The stricter constraint wins. If `harness validate` says a file is required but `harness linter validate` says its contents violate a rule, fix the contents to satisfy both. Escalate if truly irreconcilable.

---

# Harness Dependency Health

> Analyze structural health of the codebase and surface problems before they become incidents.

## When to Use

- Weekly scheduled health check on the codebase
- Before major refactoring — understand current structural health
- When onboarding to a new project — assess codebase quality
- NOT for checking layer violations (use enforce-architecture)
- 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: METRICS — Compute Graph Structural Metrics

Query the graph for five key structural indicators:

1. **Hub detection**: Find nodes with high fan-in (>10 inbound `imports` edges).

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

   Hubs are single points of failure — changes to them have outsized blast radius.

2. **Orphan detection**: Find file nodes with zero inbound `imports` edges that are not entry points.

   ```
   get_relationships(nodeId=<file>, direction="inbound")
   ```

   Orphans may be dead code or missing from the module system.

3. **Cycle detection**: Use `check_dependencies` to find circular import chains.
   Cycles create fragile coupling — any change in the cycle affects all members.

4. **Deep chain detection**: Find import chains longer than N hops (default: 7).

   ```
   query_graph(rootNodeIds=[entry points], maxDepth=10, includeEdges=["imports"])
   ```

   Deep chains are fragile — a change at the bottom propagates unpredictably.

5. **Module cohesion**: For each module (directory), count internal vs external edges. Low internal cohesion (many external edges, few internal) suggests misplaced code.

#### Fallback (without graph)

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

1. **Build adjacency list**: Grep all source files for `import`/`require` statements. Parse each to extract the imported path. Build an adjacency list mapping each file to its imports.
2. **Hub detection**: From the adjacency list, count inbound edges per file. Files with >10 importers are hubs.
3. **Orphan detection**: Files with zero inbound edges that are not entry points (not `index.*`, not in `package.json` main/exports). Use glob to find all source files, then subtract those that appear as import targets.
4. **Cycle detection**: Run DFS on the adjacency list. When a back-edge is found, report the cycle path.
5. **Deep chain detection**: From entry points, DFS to find the longest import chain. Report chains exceeding 7 hops.
6. **Module cohesion (approximate)**: For each directory, count imports that stay within the directory (internal) vs imports that leave it (external). Cohesion = internal / (internal + external).
7. **Run `check_dependencies` CLI** — this works without a graph and can detect layer violations.

> Fallback completeness: ~60% — cannot compute transitive depth beyond what import parsing reveals; coupling metrics are approximate.

6. **Detect structural anomalies**: Run `detect_anomalies` to identify structural irregularities (orphaned modules, unusual coupling patterns) that indicate dependency health issues.

### Phase 2: SCORE — Calculate Health Score

Compute a weighted health score (0-100):

| Metric            | Weight | Scoring                                   |
| ----------------- | ------ | ----------------------------------------- |
| Hubs (>10 fan-in) | 25%    | 0 hubs = 100, 1-3 = 70, 4-6 = 40, >6 = 10 |
| Orphans           | 20%    | 0 = 100, 1-5 = 80, 6-15 = 50, >15 = 20    |
| Cycles            | 25%    | 0 = 100, 1 = 60, 2-3 = 30, >3 = 0         |
| Deep chains (>7)  | 15%    | 0 = 100, 1-3 = 70, >3 = 30                |
| Cohesion (avg)    | 15%    | >0.7 = 100, 0.5-0.7 = 70, <0.5 = 30       |

**Grades**: A (90-100), B (75-89), C (60-74), D (40-59), F (<40)

Check `get_decay_trends` to see how dependency health metrics have changed over time and whether current trends are improving or degrading.

### Phase 3: RECOMMEND — Generate Recommendations

For each problem found, generate a specific, actionable recommendation:

- **Hubs**: "Split `src/utils/helpers.ts` (14 importers) into domain-specific utilities"
- **Orphans**: "Remove `src/legacy/old-parser.ts` (0 importers, not an entry point)"
- **Cycles**: "Break cycle A→B→C→A by extracting shared types to `src/types/shared.ts`"
- **Deep chains**: "Consider flattening chain: entry→A→B→C→D→E→F→G (8 hops)"
- **Low cohesion**: "Module `src/services/` has 80% external edges — consider splitting"

### Output

```
## Dependency Health Report

### Score: B (78/100)

### Metrics
| Metric | Count | Score |
|--------|-------|-------|
| Hubs (>10 fan-in) | 2 | 70/100 |
| Orphans | 3 | 80/100 |
| Cycles | 0 | 100/100 |
| Deep chains (>7) | 1 | 70/100 |
| Module cohesion | 0.62 avg | 70/100 |

### Top Issues
1. **Hub**: src/utils/helpers.ts — 14 importers (split recommended)
2. **Hub**: src/types/index.ts — 12 importers (acceptable for type barrel)
3. **Orphan**: src/legacy/old-parser.ts — 0 importers
4. **Deep chain**: entry→auth→user→db→pool→config→env→loader (8 hops)

### Recommendations
1. Split src/utils/helpers.ts into domain-specific modules
2. Investigate src/legacy/old-parser.ts for removal
3. Flatten auth chain by having auth import db directly
```

## 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_relationships`, and `check_dependencies` MCP tools.

## Success Criteria

- Health score computed on 0-100 scale with letter grade (A-F)
- All five structural metrics gathered (hubs, orphans, cycles, deep chains, cohesion)
- Recommendations are specific and actionable (name files, suggest concrete fixes)
- 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                                                                                                                               |
| ---------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| "There are a few orphan files but they are probably test fixtures or configs, so I will skip investigating them" | Orphan detection explicitly excludes entry points. Files with zero inbound imports that are not entry points must be investigated.            |
| "The cycle is between two closely related files, so it is not really a problem"                                  | Cycles create fragile coupling where any change in the cycle affects all members. Even "related" files should not have circular dependencies. |
| "The health score is a B, which is good enough -- no need to act on the recommendations"                         | A hub with 14 importers is a single point of failure. "Good enough" scores mask specific structural risks that compound over time.            |

## Examples

### Example: Weekly Health Check on Monorepo

```
Input: Scheduled weekly run on project root

1. METRICS    — query_graph for hubs: 2 found (helpers.ts, index.ts)
                get_relationships for orphans: 3 found
                check_dependencies for cycles: 0 found
                query_graph for deep chains: 1 found (8 hops)
                Module cohesion average: 0.62
2. SCORE      — Weighted score: 78/100 (Grade: B)
3. RECOMMEND  — "Split helpers.ts (14 importers) into domain modules"
                "Investigate old-parser.ts for removal (0 importers)"
                "Flatten auth chain — 8 hops exceeds threshold"

Output:
  Score: B (78/100)
  Top issues: 2 hubs, 3 orphans, 1 deep chain
  3 actionable recommendations generated
```

## Gates

- **Graph preferred, fallback available.** If no graph exists, use fallback strategies (import parsing, DFS cycle detection, hub/orphan identification). Do not stop — produce the best analysis possible.
- **Systematic analysis required.** All metrics must come from graph queries (with graph) or systematic import parsing (without graph). Do not guess — parse actual import statements.

## Escalation

- **When score is F (<40)**: Flag as critical and recommend immediate architectural review.
- **When graph is stale**: Warn and suggest re-scanning before trusting results.
