---
name: domain-modeling
description: Use when a term is fuzzy, overloaded, or contradicts how the code behaves; when writing or editing a CONTEXT.md glossary; or when a hard-to-reverse decision needs recording as an ADR.
---

# Domain Modeling

Actively build and sharpen a project's domain model as you design: challenge terms, stress-test them
with scenarios, and write the glossary and the decisions down the moment they crystallise.

This is the *active* discipline. Merely **reading** `CONTEXT.md` for vocabulary is a one-line habit
any skill can do and is not this skill. Reach for this one when you are **changing** the model, not
consuming it.

## File structure

Most repos have a single context:

```
/
├── CONTEXT.md
├── docs/
│   └── adr/
│       ├── 0001-event-sourced-orders.md
│       └── 0002-postgres-for-write-model.md
└── src/
```

A `CONTEXT-MAP.md` at the root means the repo has several contexts, and the map points to where each
one lives:

```
/
├── CONTEXT-MAP.md
├── docs/adr/                     ← system-wide decisions
└── src/
    ├── ordering/
    │   ├── CONTEXT.md
    │   └── docs/adr/             ← context-specific decisions
    └── billing/
        ├── CONTEXT.md
        └── docs/adr/
```

Create files lazily, only once there is something to write. No `CONTEXT.md` yet? Create it when the
first term is resolved. No `docs/adr/`? Create it when the first ADR is needed.

## During the session

### Challenge against the glossary

When a term conflicts with the language already in `CONTEXT.md`, call it out immediately.

> "Your glossary defines *cancellation* as X, but you seem to mean Y here. Which is it?"

### Sharpen fuzzy language

When a term is vague or overloaded, propose a precise canonical one.

> "You're saying *account*: do you mean the Customer or the User? Those are different things."

### Discuss concrete scenarios

When domain relationships are on the table, stress-test them with specific scenarios. Invent the
edge cases that force the boundaries between concepts to become precise.

### Cross-reference with the code

When a claim is made about how something works, check whether the code agrees, and surface any
contradiction.

> "The code cancels whole Orders, but you just said partial cancellation is possible. Which is right?"

The schema is the highest-signal place to check, because it is where the domain nouns are declared
rather than merely used. In a Convex project that is `convex/schema.ts`; elsewhere it is whatever
file defines the tables or types. A term that appears in conversation but nowhere in the schema is
either missing from the model or is not really a domain term.

### Update CONTEXT.md inline

When a term resolves, write it to `CONTEXT.md` right then. Do not batch them: capture each as it
happens, because the precision is what fades between now and the end of the session. Use the format
in [CONTEXT-FORMAT.md](CONTEXT-FORMAT.md).

`CONTEXT.md` is a glossary and nothing else. Keep implementation details, specs, and scratch notes
out of it.

### Offer ADRs sparingly

Offer an ADR only when all three are true:

1. **Hard to reverse**: the cost of changing your mind later is meaningful.
2. **Surprising without context**: a future reader will wonder "why on earth did they do it this
   way?"
3. **The result of a real trade-off**: genuine alternatives existed and one was picked for specific
   reasons.

Missing any one of the three, skip it. Use the format in [ADR-FORMAT.md](ADR-FORMAT.md).

## Done when

- Every term resolved this session is in `CONTEXT.md`, in the house format, with its rejected
  synonyms under `_Avoid_`.
- No implementation detail has leaked into `CONTEXT.md`.
- Every contradiction found between a stated claim and the code was surfaced, not silently resolved.
- An ADR exists for each decision meeting all three tests, and for none that miss one.
