diff --git a/AGENTS.md b/AGENTS.md index 964f367..9f95a58 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,8 +9,10 @@ Before planning or implementing product work, read: 1. [`CONTEXT.md`](CONTEXT.md) for canonical domain language. 2. [`docs/product/mastermind-product-brief.md`](docs/product/mastermind-product-brief.md) for scope and non-goals. 3. [`docs/architecture/native-mastermind.md`](docs/architecture/native-mastermind.md) for system boundaries. -4. [`docs/privacy/local-first-data-contract.md`](docs/privacy/local-first-data-contract.md) for normative data rules. -5. [`docs/product/mvp-acceptance.md`](docs/product/mvp-acceptance.md) for completion criteria. +4. [`docs/architecture/system-patterns.md`](docs/architecture/system-patterns.md) and [`docs/architecture/swift-patterns.md`](docs/architecture/swift-patterns.md) for design and implementation standards. +5. [`docs/development/commenting-standard.md`](docs/development/commenting-standard.md) for documentation rules. +6. [`docs/privacy/local-first-data-contract.md`](docs/privacy/local-first-data-contract.md) for normative data rules. +7. [`docs/product/mvp-acceptance.md`](docs/product/mvp-acceptance.md) for completion criteria. ADRs under `docs/adr` explain hard-to-reverse decisions. When legacy code or documentation conflicts with the canonical context, the canonical context wins. @@ -51,6 +53,19 @@ Use the exact terms in `CONTEXT.md`. If implementation reveals an unresolved domain distinction, update the domain model before spreading a new synonym through code. +## Review Checklist + +При проверке кода (Code Review) обязательно убедитесь в соблюдении следующих пунктов: + +- [ ] Соблюдено Dependency Rule: зависимости направлены внутрь модулей. +- [ ] Все внешние I/O и межмодульные взаимодействия закрыты протоколами (Application Ports). +- [ ] Состояние инкапсулировано в `actor` или защищено Swift 6 Concurrency. +- [ ] Отсутствуют `Task.detached` без явного обоснования и управления жизненным циклом. +- [ ] Все публичные и семантически значимые декларации снабжены русским DocC. +- [ ] Новые TODO/FIXME содержат ссылку на issue. +- [ ] Не нарушен Local-First Data Contract: сырые данные не сохраняются, секреты в Keychain. +- [ ] Код соответствует нормативным паттернам из Architecture Playbook. + ## Local-first requirements - Raw screen frames, audio, OCR, and complete transcripts are ephemeral. diff --git a/README.md b/README.md index a180544..4b89033 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,10 @@ Start here before product or implementation work: - [`docs/product/mastermind-product-brief.md`](docs/product/mastermind-product-brief.md) — product boundary and MVP. - [`docs/product/companion-island.md`](docs/product/companion-island.md) — interaction model. - [`docs/product/mvp-acceptance.md`](docs/product/mvp-acceptance.md) — completion criteria. -- [`docs/architecture/native-mastermind.md`](docs/architecture/native-mastermind.md) — production architecture. +- [`docs/architecture/native-mastermind.md`](docs/architecture/native-mastermind.md) — production architecture map. +- [`docs/architecture/system-patterns.md`](docs/architecture/system-patterns.md) — normative system patterns. +- [`docs/architecture/swift-patterns.md`](docs/architecture/swift-patterns.md) — Swift implementation standards. +- [`docs/development/commenting-standard.md`](docs/development/commenting-standard.md) — documentation rules. - [`docs/privacy/local-first-data-contract.md`](docs/privacy/local-first-data-contract.md) — normative privacy and data rules. - [`docs/adr`](docs/adr) — hard-to-reverse decisions and their rationale. diff --git a/docs/adr/0005-strict-clean-capability-architecture.md b/docs/adr/0005-strict-clean-capability-architecture.md new file mode 100644 index 0000000..5cfb641 --- /dev/null +++ b/docs/adr/0005-strict-clean-capability-architecture.md @@ -0,0 +1,46 @@ +# ADR 0005: Strict Clean Architecture and Capability Modules + +## Context + +Mastermind is a complex macOS application with multiple responsibilities: continuous capture, knowledge extraction, local graph management, and AI assistance. To ensure maintainability, testability, and clear ownership of privacy boundaries, we need a robust architectural structure. + +## Decision + +We adopt a **Strict Clean Architecture** organized around **Capability Modules**. + +### 1. Capability Modules + +The codebase is divided into stable capability boundaries: + +- **AppShell**: Orchestration, lifecycle, and composition root. +- **Observation**: Collectors and raw evidence acquisition. +- **Knowledge**: The Context Graph, projection, and retrieval logic. +- **Assistant**: AI sessions, provider routing, and prompt management. +- **Trust**: Activity logging, health monitoring, and privacy enforcement. +- **Infrastructure**: Shared utilities, encryption, and low-level storage. + +### 2. Strict Clean Architecture + +Each module follows Clean Architecture principles: + +- **Entities**: Pure domain models and logic (inner-most). +- **Use Cases/Services**: Application-specific business rules. +- **Interface Adapters**: Controllers, presenters, and gatekeepers. +- **Frameworks & Drivers**: External tools like ScreenCaptureKit, SQLite, and sidecar clients (outer-most). + +### 3. Compile-Time Dependency Rule + +- Dependencies flow **inwards**: outer layers depend on inner layers. +- Modules communicate through **Application Ports** (protocols). +- **Protocols are required** at module boundaries and for all I/O (adapters). +- Internal module logic does not require protocols for every internal function or value type, avoiding unnecessary boilerplate. + +### 4. Enforcement + +- Boundaries are enforced by separate Swift targets/modules where possible. +- The **Composition Root** (in AppShell) is the only place where concrete adapters are instantiated and injected. + +## Consequences + +- **Pros**: Clearer boundaries, easier to mock dependencies for testing, better isolation of sensitive data processing, and independent evolution of capabilities. +- **Cons**: Higher initial setup cost for new modules and mandatory boilerplate for cross-module communication. diff --git a/docs/architecture/native-mastermind.md b/docs/architecture/native-mastermind.md index fbfc8eb..0cd4680 100644 --- a/docs/architecture/native-mastermind.md +++ b/docs/architecture/native-mastermind.md @@ -4,6 +4,12 @@ This document defines the production architecture for Mastermind. Domain language comes from [`../../CONTEXT.md`](../../CONTEXT.md), product scope from [`../product/mastermind-product-brief.md`](../product/mastermind-product-brief.md), and privacy invariants from [`../privacy/local-first-data-contract.md`](../privacy/local-first-data-contract.md). +Нормативные паттерны проектирования и реализации вынесены в отдельные документы: + +- [Системные паттерны](system-patterns.md) — взаимодействие подсистем, потоки данных и безопасность. +- [Swift Implementation Patterns](swift-patterns.md) — стандарты реализации на Swift, конкурентность и управление состоянием. +- [Стандарт комментирования](../development/commenting-standard.md) — правила документирования кода. + The production application lives under `native/Mastermind`. `native/MastermindPOC` is a capability reference, not the production architecture. The Electron application is legacy source material and is not part of the production runtime. ## Runtime boundary diff --git a/docs/architecture/swift-patterns.md b/docs/architecture/swift-patterns.md new file mode 100644 index 0000000..4ba8ee8 --- /dev/null +++ b/docs/architecture/swift-patterns.md @@ -0,0 +1,83 @@ +# Swift Implementation Patterns Mastermind + +Этот документ описывает нормативные паттерны реализации кода на Swift. + +## 1. Concurrency & State Ownership + +**Problem**: Состояние гонки (race conditions) и неопределённое поведение при многопоточности. +**Rule**: Каждая stateful-возможность (Capability) или сервис принадлежат конкретному `actor`. Межмодульный обмен — только через `Sendable` неизменяемые типы (value types). `MainActor` используется исключительно для UI-проекций. +**Apply when**: При проектировании хранилищ, сервисов и вью-моделей. +**Avoid**: Использование `lock`, `DispatchQueue` для синхронизации состояния вручную; захват мутабельного состояния в замыканиях. +**Trade-offs**: Требует понимания Swift Concurrency и использования `await`. +**Verification**: Swift 6 Strict Concurrency не должен выдавать предупреждений и ошибок. + +## 2. Bounded Async Streams + +**Problem**: Неконтролируемое накопление событий в очередях (backpressure) приводит к утечкам памяти и задержкам. +**Rule**: Все `AsyncStream` должны иметь ограниченный буфер (bounded) и явную политику обработки переполнения (`dropOldest`, `dropNewest` или `coalesce`). +**Apply when**: Для потоков аудио-фреймов, скриншотов и событий UI. +**Avoid**: Создание неограниченных потоков событий. +**Verification**: Каждый стрим должен иметь тесты на поведение при переполнении. + +## 3. Lightweight UDF (Unidirectional Data Flow) + +**Problem**: Сложная двусторонняя синхронизация UI и бизнес-логики. +**Rule**: Использование однонаправленного потока данных: Immutable State → View → Intent (Action) → Service/Reducer → New State. Без обязательной зависимости от тяжелых фреймворков (TCA). +**Apply when**: В реализации Companion Island и экранов управления. +**Avoid**: Прямая мутация состояния из View; использование `Binding` для бизнес-логики. +**Verification**: View зависит только от `State` и отправляет `Intents`. + +## 4. Boundary State Machines + +**Problem**: Неявные переходы между состояниями (например, Collectors) приводят к трудновоспроизводимым багам. +**Rule**: Использование явных конечных автоматов (State Machines) для жизненного циклаCollectors, сессий и миграций. Недопустимые переходы должны быть невозможны на уровне типов. +**Apply when**: Управление жизненным циклом сложных компонентов. +**Avoid**: Большое количество разрозненных `Bool` флагов для описания состояния. +**Verification**: Unit-тесты покрывают матрицу переходов. + +## 5. Validated Value Types + +**Problem**: Проброс примитивов (String, Int) через все слои приводит к потере смысла и ошибкам валидации. +**Rule**: Использование отдельных типов-обёрток для доменных понятий (ID, Timestamp, Confidence). Проверка инвариантов происходит при создании типа. +**Apply when**: Все доменные сущности и параметры портов. +**Avoid**: Использование `String` для ID или `Double` для Confidence без обёртки. +**Verification**: Код компилируется только при передаче правильных типов; невозможны "пустые" или некорректные значения. + +## 6. Manual Composition Root + +**Problem**: Глобальные синглтоны и Service Locator делают зависимости неявными. +**Rule**: Использование ручного внедрения зависимостей (Constructor Injection) в единственной точке входа (Composition Root). Глобальные мутабельные синглтоны запрещены. +**Apply when**: Инициализация приложения в `AppShell`. +**Avoid**: Использование `shared` instance для бизнес-логики. +**Verification**: Все зависимости можно подменить (mock) в тестах без изменения кода модулей. + +## 7. Workflow-Sized Services + +**Problem**: Use cases, которые делают слишком мало (один метод) или слишком много (весь модуль). +**Rule**: Application Service должен отражать осмысленный пользовательский или системный воркфлоу (например, `AssistantSessionService`) и оркестровать несколько портов. +**Avoid**: Создание класса UseCase для каждой мелкой функции; "божественные" объекты-координаторы. +**Verification**: Сервис покрывает логически связанную группу действий. + +## 8. Typed Failure States + +**Problem**: Обобщённые ошибки `Swift.Error` не дают понимания, как на них реагировать. +**Rule**: Ожидаемые ошибки моделируются как типизированные состояния (Enum). Ошибки адаптеров переводятся в доменные ошибки на границе модуля. +**Apply when**: Возврат результатов из портов и сервисов. +**Avoid**: Проброс `NSError` или `URLError` в доменные слои. +**Verification**: UI может точно отобразить причину сбоя на основе типа ошибки. + +## 9. Structured Task Ownership + +**Problem**: Утечки задач (detached tasks) и сложности с отменой (cancellation). +**Rule**: Каждая долгоживущая `Task` принадлежит владельцу жизненного цикла и отменяется при его завершении. `Task.detached` запрещён, кроме системных воркеров. +**Apply when**: Запуск Collectors и фоновой обработки. +**Avoid**: "Fire-and-forget" задачи без сохранения ссылки на отмену. +**Verification**: Deinit объекта приводит к остановке всех запущенных им задач. + +## 10. Dedicated Executors for Blocking Work + +**Problem**: Блокировка потока актора или MainActor тяжелыми вычислениями. +**Rule**: Все блокирующие операции (SQLite, ML, PCM) выносятся на выделенные очереди или исполнители (Dedicated Executors/Queues). Оркестрация акторов не должна выполнять тяжелую работу. +**Apply when**: I/O, обработка медиа, криптография. +**Avoid**: Выполнение `Data(contentsOf:)` или сложных циклов на MainActor. +**Verification**: Профилирование в Instruments не показывает блокировок UI потока. diff --git a/docs/architecture/system-patterns.md b/docs/architecture/system-patterns.md new file mode 100644 index 0000000..e2de213 --- /dev/null +++ b/docs/architecture/system-patterns.md @@ -0,0 +1,85 @@ +# Системные паттерны Mastermind + +Этот документ описывает нормативные паттерны взаимодействия подсистем Mastermind. + +## 1. Capability-Oriented Clean Architecture + +**Problem**: Высокая связность между захватом, хранилищем и UI мешает тестированию и безопасности. +**Rule**: Каждая функциональная область (Capability) инкапсулирована в отдельный модуль с чёткими границами. Взаимодействие происходит через порты (протоколы). +**Apply when**: При добавлении новой крупной функциональности (например, новый вид захвата). +**Avoid**: Прямой импорт конкретных реализаций (Adapters) между модулями. +**Trade-offs**: Требует больше кода для инициализации (Dependency Injection). +**Verification**: Запрещены перекрёстные импорты в Swift модулях; Unit-тесты используют Mock-реализации портов. + +## 2. Ports & Async Events + +**Problem**: Глобальные шины событий (EventBus) делают зависимости неявными и затрудняют отладку. +**Rule**: Запросы и команды идут через явные порты (Application Ports). Факты о произошедшем передаются через типизированные асинхронные потоки событий (Typed Async Events). Глобальная шина запрещена. +**Apply when**: Для межмодульного взаимодействия. +**Avoid**: Использование `NotificationCenter` или глобальных `ObservableObject`. +**Trade-offs**: Требует явной оркестрации в Composition Root. +**Verification**: Каждый исходящий поток событий должен быть частью интерфейса порта модуля. + +## 3. Observation Ledger + +**Problem**: Прямая запись результатов захвата в граф знаний приводит к потере контекста и невозможности переобработки данных. +**Rule**: Collectors записывают только неизменяемые "свидетельства" (Observations) в лог (Ledger). Только Knowledge Pipeline читает этот лог. +**Apply when**: При обработке любого потока данных из источников (Sources). +**Avoid**: Прямое обновление Facts или Entities из Collectors. +**Trade-offs**: Увеличивает объём хранимых данных на диске до момента очистки (Retention). +**Verification**: База данных содержит таблицу `Observations` с Provenance. + +## 4. Idempotent Projectors & Durable Checkpoints + +**Problem**: Сбой во время обработки Observations может привести к дублированию или потере знаний в графе. +**Rule**: Проекторы (Projectors) читают лог Observations и обновляют граф, сохраняя контрольные точки (Checkpoints). Процесс должен быть идемпотентным. +**Apply when**: При преобразовании сырых данных в Assertions и Facts. +**Avoid**: Логика проекции, зависящая от текущего времени или внешнего состояния вне лога. +**Trade-offs**: Усложняет логику обновления графа. +**Verification**: Перезапуск проектора с одного и того же чекпоинта должен приводить к идентичному состоянию графа. + +## 5. Capability-Specific Persistence Ports + +**Problem**: Общие репозитории (Generic Repository) скрывают специфичные требования к данным и производительности. +**Rule**: Каждый модуль определяет свои узкие порты для работы с данными (например, `AppendObservation`, `QueryContext`). Реализация за скрытым SQLite/SQLCipher адаптером. +**Avoid**: Использование общего DAO или прямого доступа к БД вне адаптера. +**Verification**: Интерфейсы портов содержат только те методы, которые реально нужны данному модулю. + +## 6. Central Egress Gate & Privacy Envelopes + +**Problem**: Риск случайной отправки конфиденциальных данных (PII) в облако. +**Rule**: Весь исходящий трафик к внешним провайдерам проходит через единый Egress Gate. Данные передаются в типизированных конвертах (Privacy Envelopes) с метаданными о классификации. +**Apply when**: Любая передача данных за пределы Mac (Cloud Providers). +**Avoid**: Прямые сетевые запросы из Assistant или других модулей. +**Trade-offs**: Единая точка отказа и бутылочное горлышко производительности. +**Verification**: Egress Gate блокирует любые данные без явного Provider Context Permission. + +## 7. Work Scheduler & Budgets + +**Problem**: Непрерывный захват и ML-обработка могут замедлять UI или разряжать батарею. +**Rule**: Центральный планировщик распределяет задачи по приоритетам и бюджетам ресурсов. Аудио и интерактив всегда выше фоновой индексации. +**Avoid**: Запуск `Task.detached` без указания приоритета и лимитов. +**Trade-offs**: Может увеличивать задержку (latency) для фоновых задач. +**Verification**: Приложение снижает активность в Low Power Mode. + +## 8. Bounded Derived Caches + +**Problem**: Кэширование может приводить к несогласованности данных и утечкам памяти. +**Rule**: Все кэши ограничены (bounded), принадлежат конкретным акторам (actor-owned) и могут быть полностью перестроены из Context Store. +**Apply when**: Для OCR, embeddings и UI элементов. +**Avoid**: Использование глобального `NSCache` без ограничений по времени и размеру. +**Verification**: Unit-тесты проверяют очистку кэша при достижении лимитов. + +## 9. Structured Local Tracing + +**Problem**: Текстовые логи бесполезны для отладки сложных распределённых процессов без передачи контента. +**Rule**: Использование структурированных спанов и событий с Correlation IDs (SourceID, ObservationID). Redacted metadata — только технические детали. +**Avoid**: Логирование распознанного текста или аудио-транскриптов. +**Verification**: Логи не содержат персональных данных пользователя, но позволяют проследить путь конкретной Observation. + +## 10. Versioned Boundaries + +**Problem**: Изменение формата данных (ASR, LLM, Export) ломает совместимость. +**Rule**: Все границы (Sidecars, Providers, Archives) используют типизированные DTO с версионированием и Contract Tests. Tolerant Reader обязателен. +**Avoid**: Сериализация внутренних доменных типов напрямую. +**Verification**: Наличие тестов на обратную совместимость схем. diff --git a/docs/development/commenting-standard.md b/docs/development/commenting-standard.md new file mode 100644 index 0000000..ea30d64 --- /dev/null +++ b/docs/development/commenting-standard.md @@ -0,0 +1,80 @@ +# Стандарт комментирования Mastermind + +Этот документ устанавливает правила документирования и комментирования кода в Swift-проекте Mastermind. + +## 1. Язык и стиль + +- **Язык**: Все комментарии, документация DocC и пометки TODO/FIXME пишутся на **русском языке**. +- **Стиль**: Лаконичный, технический, без лишних слов. Используйте DocC для всех семантически значимых деклараций. + +## 2. Обязательный DocC + +DocC (тройной слэш `///`) обязателен для следующих элементов: + +- Все типы (Struct, Class, Enum, Actor, Protocol). +- Все требования протоколов. +- Все функции, методы и инициализаторы. +- Все свойства (properties), имеющие самостоятельный доменный или технический смысл. + +**Исключения**: + +- Локальные переменные внутри функций. +- Очевидные элементы тестовых фикстур (если их смысл понятен из названия). +- Однородные `enum cases` (можно документировать одной группой перед перечислением). + +## 3. Формат DocC (Concise Semantic DocC) + +**Правила**: + +- Первая строка — одно предложение, описывающее роль или контракт элемента. +- Секции `- Parameters:`, `- Returns:`, `- Throws:` добавляются только если они несут дополнительную информацию. +- **Запрещено**: + - Пустые секции. + - Дословный пересказ сигнатуры (например, `/// Возвращает строку` для функции `func getString() -> String`). + - Комментарии ради комментариев. + +**Пример**: + +```swift +/// Обрабатывает входящий аудио-фрейм и извлекает наблюдения. +/// +/// - Parameter frame: PCM данные в формате 16 кГц моно. +/// - Throws: `AudioError.invalidFormat`, если данные повреждены. +func process(frame: PCMFrame) throws { ... } +``` + +## 4. Внутренние комментарии (Inline) + +Используйте двойной слэш `//` только в следующих случаях: + +- **Почему (Rationale)**: Объяснение нетривиального архитектурного решения. +- **Инварианты**: Описание условий, которые должны соблюдаться в этом блоке кода. +- **Безопасность и Concurrency**: Пояснения по поводу владения данными или специфики потоков. +- **OS Quirks**: Описание обходных путей (workarounds) для особенностей macOS/AppKit. + +**Запрещено**: + +- "Narrating comments" — пересказ того, что делает код (например, `// увеличиваем счетчик`). +- Закомментированный код (удаляйте его, история есть в Git). + +## 5. Навигация и пометки + +### MARK + +Используйте `// MARK: -` для разделения больших файлов на смысловые секции. + +- Группируйте методы расширений (extensions) по протоколам, которым они соответствуют. +- Не используйте MARK для одиночных методов. + +### TODO и FIXME + +Использование этих пометок разрешено только с указанием ссылки на задачу (issue). + +- `// TODO(#123): Описание задачи и что именно нужно сделать.` +- `// FIXME(#456): Описание нарушения или риска, который нужно устранить.` + +## 6. Актуальность + +- Комментарий, не соответствующий коду — это дезинформация. +- При изменении контракта функции или логики типа, комментарий **обязан** быть обновлён в том же коммите. +- Устаревшие комментарии должны безжалостно удаляться. diff --git a/docs/product/mvp-acceptance.md b/docs/product/mvp-acceptance.md index 421e5a7..4a673c8 100644 --- a/docs/product/mvp-acceptance.md +++ b/docs/product/mvp-acceptance.md @@ -85,3 +85,13 @@ Given that enabled Collectors have observed normal work, when the user opens the - Manual tests cover macOS permissions, microphone, system audio, screen exclusion, primary-display changes, Launch at Login, sleep/wake, Low Power Mode, and relaunch while paused. - Logs and fixtures contain no captured user content. - Canonical documentation and implementation vocabulary agree with `CONTEXT.md`. + +## Architectural compliance + +- [ ] Code follows **Strict Clean Architecture** with capability modules. +- [ ] Dependency Rule is enforced at compile-time between targets. +- [ ] No global EventBus; communication uses ports and typed async streams. +- [ ] Context Graph updates are performed by idempotent projectors with durable checkpoints. +- [ ] Privacy-sensitive egress is gated by a central fail-closed Egress Gate. +- [ ] Swift 6 Strict Concurrency is enabled and produces no warnings. +- [ ] All semantic declarations have Russian DocC per the **Commenting Standard**.