# AGENTS.md — Write the intent so reviews converge

Guidance for any coding agent (Cursor, Claude Code, Codex, …) working in this repo.
Tool-agnostic and language-neutral.

**One principle: move the context out of your head and put it beside the code.**

"This branch is dead on our target." "This function is null-safe." "I left that out
on purpose." If that reasoning lives only in your head or in a PR description, every
review asks again. An AI reviewer is the relentless junior who asks on *every* PR.
The cure is a comment, not an argument.

An AI review reads rationale comments that carry a ticket number, and when the grounds
hold, it stops re-flagging. These habits are what close a finding for good instead of
letting it recur.

## Rules

### 1. Rebuttals belong in code comments, not PR descriptions

A PR description is volatile. The next review cannot read it, so a rebuttal filed
there comes back. Put the reason next to the code, with a ticket number.

```
/* Iterator safety (reviewed, #1234): delete() swaps node links and frees
 * only the removed node. A pre-fetched cursor always survives. */
```

The review verifies the *grounds*, not the comment's presence. A rationale that does
not match the code gets re-flagged despite the comment. **A comment is not a mute
button.**

The number must reference a real ticket. A made-up number is a formality, not a rebuttal.

### 2. Never leave a bare TODO

Decided against it? Say so, with the reason. Genuinely deferred? Attach a ticket number.

```
Bad:   /* TODO: logging and alarm */

Good:  /* Telemetry intentionally omitted (#1234): deletion is already
        * observable through the change-notify event. */

Good:  /* TODO(#4001): rate-limited alarm once the alerting infra lands */
```

### 3. Concurrency comments say WHY and WHO contends

Let a reviewer verify the locking instead of guessing.

```
/* The receive path walks the same structure the daemon, the timer, and the
 * notifier mutate under the write lock. Take the read lock for the walk and
 * decide on a copy. */
```

### 4. Invariants belong to the machine, not to the comment

A comment informs a human. An assertion stops the future violator.

| Assumption | Where it belongs |
|---|---|
| Layout, size | compile-time assertion |
| Lock discipline | runtime assertion in the shared accessor |
| Data invariant | a test |

### 5. State a function's contract where it is defined

Null tolerance, return conventions, ownership. One line at the definition, so callers
(and reviews of callers) do not have to guess or escalate.

```
/* Null-tolerant: returns null on null input. Safe to call after teardown. */
```

### 6. Put the boundary meaning in the name

`end` reads as exclusive. If it is the inclusive last element, call it `last`.
**A name is a contract**, and a mismatch is where off-by-one lives. If you cannot
rename it, comment the convention at the call site.

### 7. State build and configuration gates at the function head

Reviews do not read config files, and most humans don't either. If a function compiles
only under a flag, or is dead on this target, say so at the top.

```
/* Compiled only when FEATURE_X is enabled. Not enabled on this target
 * (dead code here). */
```

### 8. Fix the class, not the instance

When a review finds one case of a pattern, grep the file and the module for its
siblings and fix them in the same pass. Otherwise the next review finds the next
sibling, forever.

If you add a safety wrapper, audit every caller's contract in the same commit.

### 9. A rationale comment is a claim. Keep it true.

Rationale and contract comments are true when written and rot when the code they
describe changes. If you modify behavior such a comment relies on (its locking, its
null handling, its ownership), re-verify the comment in the same commit.

**A stale safety claim is worse than none:** it silences the review exactly where the
code just moved.

## Before you push

- [ ] Every finding I dismissed → reason now lives in a code comment with a ticket number?
- [ ] No bare TODO left → "intentionally omitted + why", or `TODO(#1234)`?
- [ ] New or changed locking → does the comment name who contends?
- [ ] Layout, lock, and data assumptions → moved into assertions or tests?
- [ ] Fixed one case of a pattern → grepped siblings and swept them in this pass?
- [ ] Touched code a rationale comment describes → is the comment still true?
- [ ] Merged only after the review completed?
