refactor: update architecture documentation and add commenting standards
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 потока.
|
||||
@@ -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<T>) скрывают специфичные требования к данным и производительности.
|
||||
**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**: Наличие тестов на обратную совместимость схем.
|
||||
Reference in New Issue
Block a user