document repository lookups

This commit is contained in:
Yisroel Baum 2026-05-25 08:14:16 +03:00
parent b44830fa53
commit 3bfcdfd0cc
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
2 changed files with 32 additions and 10 deletions

View file

@ -20,6 +20,9 @@ intentionally omitted here - update this section as entities land.
- Do not write unit tests for concrete repository implementations
(e.g. `Postgres*Repository`). They are exercised by e2e tests.
Use cases are tested with fake repositories.
- Repository methods that find records by a foreign key should accept
the related entity, not a raw id (e.g. `findBySet(Set $set)`, not
`findBySetId(int $setId)`).
- Use cases: business logic with Request objects
- When throwing exceptions, add `@throws` docblock
- Fakes: in-memory implementations for testing
@ -50,16 +53,33 @@ to be added to the repo; the Nix flake already provides
Constructs LLMs default to that this project forbids. Name the trap
explicitly so you catch yourself before writing it.
| Anti-pattern | Forbidden | Required |
|---|---|---|
| Arrow function | `fn ($x) => $x->getId()` | `function ($x) { return $x->getId(); }` |
| Inline FQCN type | `function f(): \Psr\Http\Message\ResponseInterface` | `use Psr\Http\Message\ResponseInterface;` then `function f(): ResponseInterface` |
| Inline `::class` | `Container::get(\App\Foo\Bar::class)` | `use App\Foo\Bar;` then `Container::get(Bar::class)` |
| Default param | `function f(int $count = 10)` | `function f(int $count)` |
| Default in fake | `public function create(Dto $dto, bool $strict = true)` | no default; every caller passes a value |
| Lookup returns stored ref | `return $this->items[$id] ?? null;` | rebuild a new instance with the stored fields |
| Short variable name | `$t`, `$n`, `$res`, `$req`, `$e` | `$text`, `$node`, `$response`, `$request`, `$exception` |
| Em dash | `// fetches user — by email` | `// fetches user - by email` |
- Arrow function:
- Forbidden: `fn ($node) => $node->getId()`
- Required: `function ($node) { return $node->getId(); }`
- Inline FQCN type:
- Forbidden: `function f(): \Psr\Http\Message\ResponseInterface`
- Required: import `ResponseInterface`, then return `ResponseInterface`
- Inline `::class`:
- Forbidden: `Container::get(\App\Foo\Bar::class)`
- Required: import `Bar`, then call `Container::get(Bar::class)`
- Default param:
- Forbidden: `function f(int $count = 10)`
- Required: `function f(int $count)`
- Default in fake:
- Forbidden: `public function create(Dto $dto, bool $strict = true)`
- Required: no default; every caller passes a value
- Lookup returns stored ref:
- Forbidden: `return $this->items[$id] ?? null;`
- Required: rebuild a new instance with the stored fields
- FK lookup by id:
- Forbidden: `findBySetId(int $setId)`
- Required: `findBySet(Set $set)`
- Short variable name:
- Forbidden: one-letter or abbreviated names (`$t`, `$n`, `$res`)
- Required: explicit names (`$text`, `$node`, `$response`)
- Em dash:
- Forbidden: comment or docblock containing an em dash character
- Required: use `-`
When generating code, scan the diff for these patterns before writing it
to disk. If you catch one mid-write, rewrite that line.

View file

@ -111,6 +111,8 @@ mechanical, not aspirational - a "yes" to all is required.
(PHP or TS).
- [ ] Find/lookup repository methods return new instances, not stored
references.
- [ ] Backend repository methods that find by a foreign key accept the
related entity, not a raw id.
- [ ] No em dashes (use hyphens).
- [ ] Variable names are explicit (no `$t`, `n`, `res`, `req`, `e`, etc.).
- [ ] No `any` in TypeScript - use concrete types or `unknown` with a