Skip to content

Commit af0e4d6

Browse files
authored
Update CLAUDE.md
1 parent 6bae556 commit af0e4d6

File tree

1 file changed

+139
-41
lines changed

1 file changed

+139
-41
lines changed

CLAUDE.md

Lines changed: 139 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,93 @@
22

33
ЦЕЛЬ: Создавать математически доказуемые решения через функциональную парадигму с полным разделением чистых вычислений и контролируемых эффектов.
44

5-
Всегда начинай свой ответ с постановки задачи Deep Research "I am looking for code that does <requested functionality>, is there existing code that can do this?" Любое решение строится на математических инвариантах, доказуемых свойствах и проверяемых источниках. Код создается только после формального понимания проблемы и построения архитектурной модели.
5+
МОДЕЛЬ РАССУЖДЕНИЯ:
6+
7+
- Не выдавать “личные мнения”. Формировать вывод как результат симуляции профессионального обсуждения релевантных ролей
8+
(архитектор Effect/FP, ревьюер типов, страж CORE↔SHELL, тест-инженер).
9+
- Если запрос сформулирован как “что думаешь”, отвечать в терминах аргументов ролей и выбирать решение
10+
по критериям инвариантов, типовой безопасности и тестируемости (если пользователь явно просит выбор — выбрать и обосновать).
11+
12+
ПРАВИЛО ПРОЦЕССА (НЕ ФОРМАТ ОТВЕТА):
13+
В начале работы (внутренне) формулировать Deep Research вопрос:
14+
"I am looking for code that does <requested functionality>, is there existing code that can do this?"
15+
Далее:
16+
17+
- если доступен проект/код — сперва искать и переиспользовать существующие паттерны (минимальный корректный diff),
18+
- если проект недоступен — опираться на предоставленный контекст и явно фиксировать допущения,
19+
- код писать только после формального понимания задачи (типы/инварианты → архитектура → код → тесты),
20+
- источники указывать только если реально использован внешний материал; иначе `SOURCE: n/a`.
21+
22+
ИНСТРУМЕНТАЛЬНОЕ ПОВЕДЕНИЕ (ОБЯЗАТЕЛЬНО, НЕ ФОРМАТ ОТВЕТА):
23+
24+
- Агент всегда использует доступные инструменты среды (терминал, поиск по проекту, запуск тестов/скриптов, анализ сборки, web-ресёрч при необходимости)
25+
для ресёрча, проверки гипотез и выполнения действий. Приоритет: проверяемость, воспроизводимость, минимальный риск.
26+
- Агент не предлагает “гайд” как замену действия. Если действие возможно выполнить инструментами — агент выполняет его сам,
27+
затем сообщает, что было сделано и как повторить.
28+
- Любые инструкции (команды/процедуры) агент даёт только после собственной проверки на доступной среде.
29+
Если проверить невозможно — явно фиксирует ограничение и перечисляет команды для воспроизведения и верификации.
30+
- Всегда начинать с изучения задачи инструментами: состояние проекта, существующие паттерны, интеграционные точки, регрессии.
31+
- Всегда завершать верификацией инструментами: сборка/типчек/тесты/линтеры/минимальные проверки инвариантов.
32+
- Команды/вызовы должны быть реальными и проверяемыми; никаких вымышленных/placeholder-команд.
33+
34+
ПЕТЛЯ РЕСЁРЧА (ПРИ НЕОПРЕДЕЛЁННОСТИ ИЛИ СБОЯХ):
35+
36+
- поиск по кодовой базе/проекту/докам (локально) → запуск минимального скрипта/теста гипотезы → уточнение модели типов/инвариантов
37+
- при необходимости: web-ресёрч и верификация найденного через инструменты
38+
- если любой последующий шаг не проходит (сборка/тест/линтер/инвариант) — немедленно вернуться в петлю ресёрча.
39+
40+
Любое решение строится на математических инвариантах, доказуемых свойствах и проверяемых источниках. Код создается только после формального понимания проблемы и построения архитектурной модели.
41+
42+
---
43+
44+
<example>
45+
user: Закоммить изменения.
46+
assistant:
47+
- инструменты: проверю состояние и дифф, чтобы зафиксировать точный набор изменений.
48+
- [run_terminal_cmd("git status")]
49+
- [run_terminal_cmd("git diff")]
50+
- инструменты: прогоню проверки проекта (согласно стандарту репо), чтобы коммит был верифицирован.
51+
- [run_terminal_cmd("<project_test_or_build_cmd>")]
52+
- инструменты: добавлю только релевантные файлы, затем коммит и пуш.
53+
- [run_terminal_cmd("git add <files_or_paths>")]
54+
- [run_terminal_cmd("git commit -m \"<message>\"")]
55+
- [run_terminal_cmd("git push")]
56+
- результат: изменения закоммичены; проверки прошли; шаги воспроизводимы командами выше.
57+
</example>
58+
59+
<example>
60+
user: Добавь валидацию инварианта X.
61+
assistant:
62+
- инструменты: найду существующие места, где уже формализованы похожие инварианты/типы.
63+
- [search_codebase("invariant X")]
64+
- [search_codebase("validation")]
65+
- инструменты: запущу минимальный тест/скрипт, чтобы воспроизвести текущий провал/поведение.
66+
- [run_terminal_cmd("<existing_test_cmd_or_min_repro>")]
67+
- формализация: уточню типы/контракты и границу CORE↔SHELL, затем внесу минимальный корректный diff.
68+
- инструменты: подтвержу корректность сборкой/тестами/линтерами.
69+
- [run_terminal_cmd("<build_cmd>")]
70+
- [run_terminal_cmd("<test_cmd>")]
71+
- результат: инвариант X обеспечен на уровне типов/проверок; поведение подтверждено инструментами.
72+
</example>
673

774
АРХИТЕКТУРНЫЕ ПРИНЦИПЫ:
875
═══════════════════════════════
976

1077
🏗️ **FUNCTIONAL CORE, IMPERATIVE SHELL**:
1178

1279
- CORE: Исключительно чистые функции, неизменяемые данные, математические операции
13-
- SHELL: Все эффекты (IO, сеть, БД) изолированы в тонкой оболочке
80+
- SHELL: Все эффекты (IO, сеть, БД, env/process) изолированы в тонкой оболочке
1481
- Строгое разделение: CORE никогда не вызывает SHELL
1582
- Зависимости: SHELL → CORE (но не наоборот)
1683

1784
🔒 **ТИПОВАЯ БЕЗОПАСНОСТЬ**:
1885

19-
- Никогда: `any`, `unknown`, `eslint-disable`, `ts-ignore`, `as` (кроме обоснованных случаев)
20-
- Всегда: исчерпывающий анализ union types через `.exhaustive()`
86+
- Никогда: `any`, `eslint-disable`, `ts-ignore`
87+
- `unknown`: допускается ТОЛЬКО на boundary (SHELL) как вход в декодирование (например, `@effect/schema`);
88+
после декодинга `unknown` не должен выходить наружу boundary-модуля
89+
- `as`: запрещён в обычном коде; допускается ТОЛЬКО в одном “аксиоматическом” модуле (бренды/конструкторы/константы),
90+
дальше использование без кастов
91+
- Всегда: исчерпывающий анализ union types через `.exhaustive()` / `Match.exhaustive`
2192
- Внешние зависимости: только через типизированные интерфейсы
2293
- Ошибки: типизированы в сигнатурах функций, не runtime exceptions
2394

@@ -27,19 +98,24 @@
2798
- Композиция через `pipe()` и `Effect.flatMap()`
2899
- Dependency injection через Layer pattern
29100
- Обработка ошибок без try/catch
101+
- Запрещено в продукт-коде: `async/await`, raw Promise chains (`then/catch`), `Promise.all`
102+
- Interop с Promise/исключениями — только в SHELL через `Effect.try` / `Effect.tryPromise` (с типизированным маппингом ошибок)
103+
- Ресурсы с финализацией — только через `Effect.acquireRelease` + `Effect.scoped`
30104

31105
ОБЯЗАТЕЛЬНЫЕ ТРЕБОВАНИЯ:
32106
═══════════════════════════
33107

34108
1. **ЧИСТОТА ФУНКЦИЙ**:
35109

36110
```typescript
37-
// ✅ ПРАВИЛЬНО - чистая функция
38-
const calculateTotal = (items: readonly Item[]): Money =>
39-
items.reduce((sum, item) => sum + item.price, 0 as Money)
111+
// ✅ ПРАВИЛЬНО - чистая функция (без эффектов, без мутаций)
112+
type Money = number
113+
114+
const calculateTotal = (items: ReadonlyArray<Item>): Money =>
115+
items.reduce((sum, item) => sum + item.price, 0)
40116

41117
// ❌ НЕПРАВИЛЬНО - нарушение чистоты
42-
const calculateTotal = (items: Item[]): Money => {
118+
const calculateTotalImpure = (items: Item[]): Money => {
43119
console.log("Calculating total") // ПОБОЧНЫЙ ЭФФЕКТ!
44120
return items.reduce((sum, item) => sum + item.price, 0)
45121
}
@@ -50,9 +126,9 @@ const calculateTotal = (items: Item[]): Money => {
50126
```typescript
51127
// CHANGE: <краткое описание изменения>
52128
// WHY: <математическое/архитектурное обоснование>
53-
// QUOTE(ТЗ): "<дословная цитата требования>"
129+
// QUOTE(ТЗ): "<дословная цитата требования>" | n/a
54130
// REF: <REQ-ID из RTM или номер сообщения>
55-
// SOURCE: <ссылка с дословной цитатой из внешнего источника>
131+
// SOURCE: <ссылка с дословной цитатой из внешнего источника> | n/a
56132
// FORMAT THEOREM: <∀x ∈ Domain: P(x) → Q(f(x))>
57133
// PURITY: CORE | SHELL - явная маркировка слоя
58134
// EFFECT: Effect<Success, Error, Requirements> - для shell функций
@@ -84,7 +160,7 @@ const calculateTotal = (items: Item[]): Money => {
84160

85161
```typescript
86162
// Switch statements are forbidden in functional programming paradigm.
87-
// How to fix: Use Effect.Match instead.
163+
// How to fix: Use Match with exhaustive coverage.
88164
// Example:
89165
import { Match } from "effect"
90166

@@ -154,17 +230,17 @@ const PostgresMessageRepository = Layer.effect(
154230
7. **CONVENTIONAL COMMITS С ОБЛАСТЯМИ**:
155231

156232
```bash
157-
feat(core): add message validation with mathematical constraints
233+
feat(core): add message validation with mathematical constraints
158234

159-
- Implements pure validation functions for message content
160-
- Adds invariant: ∀ msg: valid(msg) → sendable(msg)
161-
- BREAKING CHANGE: Message.content now requires non-empty string
235+
- Implements pure validation functions for message content
236+
- Adds invariant: ∀ msg: valid(msg) → sendable(msg)
237+
- BREAKING CHANGE: Message.content now requires non-empty string
162238

163-
fix(shell): resolve database connection pooling issue
239+
fix(shell): resolve database connection pooling issue
164240

165-
perf(core): optimize message sorting algorithm to O(n log n)
241+
perf(core): optimize message sorting algorithm to O(n log n)
166242

167-
docs(architecture): add formal specification for FCIS pattern
243+
docs(architecture): add formal specification for FCIS pattern
168244
```
169245

170246
8. **ОБЯЗАТЕЛЬНЫЕ БИБЛИОТЕКИ**:
@@ -181,22 +257,39 @@ const PostgresMessageRepository = Layer.effect(
181257
9. **СТРОГАЯ ТИПИЗАЦИЯ ВНЕШНИХ ЗАВИСИМОСТЕЙ**:
182258

183259
```typescript
184-
// Все внешние сервисы через Effect + Layer
185-
class DatabaseService extends Context.Tag("DatabaseService")
186-
DatabaseService,
187-
{
188-
readonly query: <T>(sql: string, params: readonly unknown[]) => Effect.Effect<T, DatabaseError>
189-
readonly transaction: <T>(op: Effect.Effect<T, DatabaseError>) => Effect.Effect<T, DatabaseError>
190-
}
191-
>() {}
192-
193-
class HttpService extends Context.Tag("HttpService")
194-
HttpService,
195-
{
196-
readonly get: <T>(url: string) => Effect.Effect<T, HttpError>
197-
readonly post: <T>(url: string, body: unknown) => Effect.Effect<T, HttpError>
198-
}
199-
>() {}
260+
// Все внешние сервисы через Effect + Layer.
261+
// Boundary-данные должны быть типизированы; "unknown" допускается только как вход в Schema decoding внутри boundary-модуля.
262+
263+
type SqlValue = string | number | boolean | null | bigint | Uint8Array | Date
264+
265+
class DatabaseService extends Context.Tag("DatabaseService")
266+
DatabaseService,
267+
{
268+
readonly query: <T>(
269+
sql: string,
270+
params: ReadonlyArray<SqlValue>
271+
) => Effect.Effect<T, DatabaseError>
272+
readonly transaction: <T>(
273+
op: Effect.Effect<T, DatabaseError>
274+
) => Effect.Effect<T, DatabaseError>
275+
}
276+
>() {}
277+
278+
type Json =
279+
| null
280+
| boolean
281+
| number
282+
| string
283+
| ReadonlyArray<Json>
284+
| { readonly [k: string]: Json }
285+
286+
class HttpService extends Context.Tag("HttpService")
287+
HttpService,
288+
{
289+
readonly get: <T>(url: string) => Effect.Effect<T, HttpError>
290+
readonly post: <T>(url: string, body: Json) => Effect.Effect<T, HttpError>
291+
}
292+
>() {}
200293
```
201294

202295
10. **ТЕСТИРОВАНИЕ С МАТЕМАТИЧЕСКИМИ СВОЙСТВАМИ**:
@@ -215,17 +308,20 @@ describe("Message invariants", () => {
215308
)
216309
)
217310

218-
// Unit тесты с мок-зависимостями (быстрые)
219-
it("should handle send message use case", async () => {
220-
const result = await pipe(
311+
// Unit тесты с мок-зависимостями (быстрые) — без async/await
312+
it.effect("should handle send message use case", () =>
313+
pipe(
221314
sendMessageUseCase(validCommand),
222315
Effect.provide(MockMessageRepository),
223316
Effect.provide(MockNotificationService),
224-
Effect.runPromise
317+
Effect.tap((messageId) =>
318+
Effect.sync(() => {
319+
expect(messageId).toEqual(expectedMessageId)
320+
})
321+
),
322+
Effect.asVoid
225323
)
226-
227-
expect(result).toEqual(expectedMessageId)
228-
})
324+
)
229325
})
230326
```
231327

@@ -246,6 +342,8 @@ describe("Message invariants", () => {
246342
- Нет прямых обращений к внешним системам в CORE
247343
- Все Effect'ы композируются через pipe()
248344
- TSDoc содержит инварианты и сложность
345+
- Нет `async/await`, raw Promise chains, `try/catch` для логики, `console.*` в продукт-коде
346+
- Любые boundary-данные декодируются (например, `@effect/schema`) прежде чем попасть в домен
249347

250348
**BEFORE MERGE**:
251349

0 commit comments

Comments
 (0)