---
name: handoff-readability
description: Enforce boring code, why-comments on non-obvious decisions, and clean interface contracts. Use in code-generation workflows. Makes rewrites cheap, reduces onboarding time, and prevents the "only the original author understands this" failure mode.
user-invocable: false
model-invocable: true
side-effects: code-edits
permission-profile: normal
triggers:
  - build
  - review
  - "*"
---

# Handoff Readability

## Iron Law

```
CODE IS READ 10X MORE THAN IT IS WRITTEN.
WRITE FOR THE READER WHO HAS ZERO CONTEXT.
BORING CODE IS A FEATURE.
```

Clever code that only the author can read is a liability. Every non-obvious decision is a future debugging session waiting to happen. Every missing comment on a "why" is a future misunderstanding that will produce a silent regression.

## Recognize Your Own Rationalizations

- "It's obvious what this does." → Obvious to you, now, with context. Not obvious at 2am during an incident to someone who didn't write it.
- "Comments are noise." → Implementation comments are often noise. *Why* comments are always signal.
- "The code is self-documenting." → Function names document *what*. Only comments document *why*.
- "I'll clean it up later." → Later is when you're two milestones ahead and the context is gone. Clean it now.

## When to Run

- During code generation (inline, as you write)
- During code review (check existing code for violations)
- Before marking a slice complete (final readability pass)

## The Three Rules

### Rule 1: Boring over clever

Prefer the solution a junior developer can read and modify. If you face a choice between:
- An elegant one-liner and a readable 5-liner → use the 5-liner
- A clever abstraction and a repeated-but-obvious pattern → repeat it until repetition is clearly worth abstracting
- A performance micro-optimization and readable code → readable code, unless the performance requirement is proven

**Exception:** performance-critical paths (must be documented with a benchmark that proves the optimization is necessary).

### Rule 2: Why-comments on every non-obvious decision

A comment is required when:
- The code does something that looks wrong but is intentional
- The code uses a non-standard approach for a reason
- A value or constant was chosen for a specific reason (not arbitrary)
- The code handles an edge case that isn't obvious from the types

Format:
```ts
// WHY: <reason the non-obvious thing is correct>
```

Examples:
```ts
// WHY: SQLite WAL mode is required here — the default journal mode causes
// write contention when multiple processes access the same DB file.
db.pragma("journal_mode = WAL");

// WHY: Retry up to 3 times with 1s backoff. The gateway has a 500ms cold-start
// window after idle; the first call will often fail.
const result = await retry(call, { times: 3, waitMs: 1000 });

// WHY: Empty array not null — callers use .length checks without null guards.
if (!data) return [];
```

### Rule 3: Clean interface contracts

Every exported function needs a contract that answers:
- **What does it return** (type + what null/undefined/empty means)
- **What are the preconditions** (what must be true for it to work)
- **What are the side effects** (writes, events, mutations)

Bad:
```ts
export function processUser(user) { ... }
```

Good:
```ts
/**
 * Validate and normalize a user record for DB insertion.
 * Returns null if the record fails validation (caller decides whether to throw).
 * Side effects: none. Pure function.
 * Precondition: user.id must be a non-empty string.
 */
export function processUser(user: RawUser): NormalizedUser | null { ... }
```

## Rewrites-Cheap Test

Before submitting a slice, ask:

1. **Could a new team member understand each function without reading its callers?**  
   If no → add why-comments or simplify.

2. **Could the core logic be replaced without touching the interface?**  
   If no → the interface is coupled to the implementation. Separate them.

3. **Are there any "magic" values without a named constant and a why-comment?**  
   If yes → name the constant and explain the value.

4. **Does every exported symbol have a contract (JSDoc with purpose + consumer)?**  
   If no → add it before marking the slice done.

## Anti-Patterns

| Pattern | Problem | Fix |
|---------|---------|-----|
| `// do the thing` | Describes what, not why | Replace with a why-comment or delete |
| `const x = 42` | Magic number | `const MAX_RETRIES = 3; // WHY: ...` |
| One-letter variables outside loops | Forces reader to track mental state | Use descriptive names |
| Deeply nested conditionals | Hard to follow control flow | Extract to named functions |
| Side effects in getters | Violates principle of least surprise | Separate reads from writes |

## Completion Criteria

- [ ] No magic values without named constants and why-comments
- [ ] Every non-obvious decision has a `// WHY:` comment
- [ ] Every exported symbol has a purpose + consumer JSDoc
- [ ] Core logic is replaceable without changing the interface
- [ ] A new team member can understand each function without external context
