
HiddenSteps — локальная персональная платформа интеллектуальной аналитики рабочих процессов
Это честное, отражающее текущее состояние дополнение к целевой карте модулей из docs/design/02-system-architecture.md. Здесь сказано, что реально построено, что проверено против настоящего бэкенда, а не мока, и чего всё ещё по-настоящему не хватает, — а не что запланировано (об этом — docs/roadmap/01-implementation-roadmap.md).
Выполните cargo build --workspace && cargo test --workspace && cargo clippy --workspace --all-targets -- -D warnings из корня репозитория. На момент написания: 12 крейтов, 193 проходящих теста, ноль предупреждений clippy, cargo fmt --check чистый — 183 теста в 11 крейтах, которым не нужны ни дисплей, ни внешний сервис, плюс 10 в hiddensteps-observation, которым нужен живой X11-дисплей (проверено там, где он есть; см. соответствующую строку). Четыре теста по замыслу помечены #[ignore] (см. ниже) и не считаются ошибками и не входят в число 193.
| Крейт | Реализует | Как проверено |
|---|---|---|
hiddensteps-domain | Базовые типы: PrivacyLevel/PrivacyState, EventSummary/SignalType, Pattern, Recommendation, AuditEntry и CapturedSignal — тип, который структурно невозможно сохранить (нет Serialize), что обеспечивает соблюдение правила сырых данных из ADR-0006 на уровне типов | Модульные тесты: round-trip уровней/упорядочивание, ограничение по TTL в Deep-режиме |
hiddensteps-security | SecretStore (ADR-0008): реальная реализация на основе OS-vault (KeyringSecretStore) и реализация в памяти (для тестов); генерация мастер-ключа через CSPRNG (возвращается в обёртке zeroize::Zeroizing, так что ключ затирается при drop, а не остаётся в освобождённой памяти); вывод ключа из парольной фразы через Argon2id для Portable Mode (PassphraseKey затирает свой производный ключ при drop, сохраняя несекретную соль). hiddensteps-event-store аналогично хранит содержащий ключ SQL-текст PRAGMA key/rekey в Zeroizing | Модульные тесты против хранилища в памяти и KDF; полный цикл с реальным хранилищем помечен #[ignore] (см. ниже) |
hiddensteps-event-store | SqlCipherEventStore (ADR-0003): полная схема из docs/design/07-database-schema.md, CRUD для состояния приватности, событий, журнала аудита, паттернов, связей паттерн↔событие, эмбеддингов паттернов (см. примечание ниже), рекомендаций, конфигурации LLM-провайдера и общих настроек, плюс delete_all_data (транзакционный; также выполняет rekey для «удаления всего», переживающего перезапуск)/export_data/count_rows (диагностика)/delete_expired_events (очистка TTL в Deep-режиме, вызывается из периодического цикла рекомендаций в apps/desktop/src-tauri — ttl_expires_at сохранялся начиная с v0.1.0, но до этого момента ничто не удаляло строки с истёкшим сроком); принудительное соблюдение внешних ключей (PRAGMA foreign_keys = ON), чтобы ON DELETE CASCADE из schema.sql для связей паттерн↔событие действительно выполнялся | 33 теста против реального файла SQLCipher: неверный ключ не открывает файл, тот же ключ корректно открывает его повторно, delete-all очищает все таблицы, включая новейшие, rekey проходит полный цикл, очистка TTL не затрагивает неистёкшие события, каскадное удаление не оставляет осиротевших связей паттерн↔событие |
hiddensteps-redaction | Движок редактирования (docs/design/05-privacy-model.md §4): детекторы на основе regex+Luhn для API-ключей/токенов/PEM-ключей/email/SSN/кредитных карт, энтропийный детектор неоднозначных секретов и политика удаления при неуверенности | 30 тестов, включая намеренно состязательные входные данные (секреты, встроенные в прозу, почти-секреты, которые секретами не являются, например git-хеши, SSN без дефисов/с пробелами, номера карт с дописанными цифрами, высокоэнтропийные токены в одном регистре) |
hiddensteps-pipeline | Конвейер событий (ADR-0006): Classify → Redact → Summarize, ограничение по уровню приватности для каждого типа сигнала, назначение TTL в Deep-режиме | 8 тестов, покрывающих удаления, вызванные редактированием, удаления из-за ограничений уровня и успешную суммаризацию |
hiddensteps-observation | ObservationSource (ADR-0005) + Linux: ActiveWindowSource (X11 GetInputFocus), FileOperationSource (inotify через notify), ClipboardMetadataSource (выделение X11, только метаданные), GlobalShortcutSource (X11 XGrabKey). Плюс файлы источников для macOS/Windows (см. ниже) | 10 из 11 тестов в этом окружении выполняются против реальных бэкендов — живого X11-дисплея (DISPLAY=:0 у WSLg) и настоящего inotify, а не моков. 1 тест (реальный захват GlobalShortcutSource) по замыслу помечен #[ignore] |
hiddensteps-llm-provider | LlmProvider (ADR-0004): клиент Ollama (с полем запроса think: Option<bool> для гибридных моделей рассуждения), клиент, совместимый с протоколом OpenAI (покрывает OpenAI/Azure/OpenRouter/Together/Groq/DeepSeek/LocalAI), клиент Anthropic Messages и автоопределение локального рантайма. Каждый клиент устанавливает таймаут запроса (build_http_client), чтобы зависший удалённый сервис не мог заблокировать вызов навсегда; Ollama передаёт max_tokens как вложенный options.num_predict | 19 тестов против mock-серверов wiremock (включая реальную проверку срабатывания таймаута и того, что Ollama действительно отправляет num_predict), плюс 2 интеграционных теста с реальной Ollama (tests/ollama_live.rs, помечены #[ignore] — см. ниже), которые нашли и исправили реальную проблему: один и тот же промпт занимал более двух минут у реальной локальной гибридной модели рассуждения с think, оставленным по умолчанию, и несколько секунд с think: Some(false) |
hiddensteps-patterns | Обнаружение паттернов (сопоставление n-граммных последовательностей скользящим окном) + граф рабочих процессов (граф переходов с весами рёбер) — Слой 1 из ADR-0010 | 16 тестов, включая прямой аналог примера «observed 31 times» из PROMPT.md и регрессионный тест того, что перекрывающиеся окна по непрерывному повторению не учитываются дважды |
hiddensteps-recommendations | Слой 2 движка рекомендаций (ADR-0010): LLM-синтез с контрактом промпта в виде структурированного JSON, валидатор нарративных противоречий и цикл повторов — важно, что числовые поля (estimated_time_saved_minutes) вообще никогда не извлекаются из вывода LLM, а только вычисляются на основе Слоя 1 | 23 теста, включая повтор при некорректном JSON, повтор при нарративном противоречии (покрывает числа прописью и каждое поле, управляемое LLM, а не только why) и извлечение JSON с учётом строк, — против скриптованного тестового провайдера |
hiddensteps-privacy-engine | Шлюз отправки в облако (docs/design/03-data-flow-diagrams.md §5) и версионирование согласий (docs/design/05-privacy-model.md §5); PrivacyGatedProvider оборачивает любой LlmProvider, так что шлюз нельзя обойти обычным путём вызова | 13 тестов, включая то, что контент Уровня 4 блокируется, даже когда предоставлены все согласия |