
HiddenSteps — une plateforme locale de renseignement sur les flux de travail personnels
Ceci est le complément honnête et à jour de la carte des modules cible de docs/design/02-system-architecture.md. Il indique ce qui est réellement construit, ce qui est vérifié contre un vrai backend plutôt qu'un mock, et ce qui manque réellement — pas ce qui est prévu (c'est le rôle de docs/roadmap/01-implementation-roadmap.md).
Exécutez cargo build --workspace && cargo test --workspace && cargo clippy --workspace --all-targets -- -D warnings depuis la racine du dépôt. Au moment où ces lignes sont écrites : 12 crates, 193 tests réussis, zéro avertissement clippy, cargo fmt --check propre — 183 sur les 11 crates qui ne nécessitent ni affichage ni service externe, plus 10 dans hiddensteps-observation qui nécessitent un affichage X11 actif (vérifié là où il en existe un ; voir cette ligne). Quatre tests sont #[ignore]d par conception (voir ci-dessous) et ne sont comptés ni comme échecs ni comme faisant partie des 193.
| Crate | Implémente | Vérifié comment |
|---|---|---|
hiddensteps-domain | Types de base : PrivacyLevel/PrivacyState, EventSummary/SignalType, Pattern, Recommendation, AuditEntry, et CapturedSignal — un type qui ne peut structurellement pas être persisté (pas de Serialize), appliquant la règle des données brutes de l'ADR-0006 au niveau du type | Tests unitaires : aller-retour/ordonnancement des niveaux, contrôle du TTL en mode Deep |
hiddensteps-security | SecretStore (ADR-0008) : vrai coffre-fort OS (KeyringSecretStore) + implémentations en mémoire (test) ; génération de clé maîtresse CSPRNG (retournée dans un wrapper zeroize::Zeroizing pour que la clé soit effacée à la libération plutôt que de subsister en mémoire libérée) ; dérivation de phrase secrète Argon2id pour le mode portable (PassphraseKey efface sa clé dérivée à la libération, conservant le sel non secret). hiddensteps-event-store conserve de même le texte SQL PRAGMA key/rekey contenant la clé dans Zeroizing | Tests unitaires contre le stockage en mémoire et la KDF ; l'aller-retour avec le vrai coffre-fort est #[ignore]d (voir ci-dessous) |
hiddensteps-event-store | SqlCipherEventStore (ADR-0003) : le schéma complet de docs/design/07-database-schema.md, CRUD pour l'état de confidentialité, les événements, le journal d'audit, les motifs, les liens motif↔événement, les plongements de motifs (voir la note ci-dessous), les recommandations, la configuration du fournisseur LLM et les paramètres génériques, plus delete_all_data (transactionnel ; effectue aussi un rekey pour un « tout supprimer » qui survit à un redémarrage)/export_data/count_rows (diagnostics)/delete_expired_events (le balayage TTL du mode Deep, appelé depuis la boucle de recommandation périodique de apps/desktop/src-tauri — ttl_expires_at était persisté depuis la v0.1.0 mais rien ne supprimait une ligne au-delà avant cela) ; application des clés étrangères () pour que le de schema.sql sur les liens motif↔événement s'exécute réellement |
Plus, en dehors de crates/ (pas dans le workspace racine — voir pourquoi ci-dessous) :
hiddensteps-event-store avec la similarité cosinus calculée en Rust, en remplacement de la table virtuelle sqlite-vec de l'ADR-0007 (voir le commentaire en haut de event-store/src/schema.sql) — charger une extension SQLite native n'était pas vérifiable dans cet environnement, et l'ADR-0007 lui-même note qu'à des volumes réalistes d'utilisateur unique, le comportement propre de sqlite-vec est une recherche exacte par force brute. Même sémantique, aucun risque d'extension native.hiddensteps-observation (src/macos/, src/windows/) sont du vrai code source complet contre des API de plateforme stables depuis longtemps (CGWindowListCopyWindowInfo ; GetForegroundWindow/GetWindowTextW/QueryFullProcessImageNameW) écrit sans chaîne d'outils macOS/Windows disponible — et les deux compilent maintenant proprement, vérifié par la matrice de jobs de . Le module macOS a d'abord nécessité une vraie correction ('s paramètres génériques par défaut non typés ne satisfaisaient pas la borne de trait de pour une clé — corrigé en le typant explicitement comme ) ; Windows a compilé proprement du premier coup.crates/crates/* est le workspace racine Cargo.toml et est entièrement compilable/testable dans cet environnement de développement Linux sans dépendances système au-delà de ce que cargo récupère. apps/desktop/src-tauri nécessite webkit2gtk-4.1 (Linux) ne serait-ce que pour compiler, ce que cet environnement ne peut pas installer (pas de sudo sans mot de passe, pas de chemin nix/gestionnaire de paquets fonctionnel — confirmé par tentative directe). Le maintenir hors du workspace signifie que cargo build --workspace reste 100 % vert ici plutôt que définitivement rouge sur un crate que personne ne peut corriger dans ce bac à sable. Il nécessite aussi sa propre table [workspace] vide dans son Cargo.toml pour la même raison — sinon Cargo tente de l'attacher à ce workspace ancêtre et échoue avec « current package believes it's in a workspace when it's not ». apps/desktop/ui n'a pas une telle contrainte et est vérifié de la même manière que le cœur Rust. Les deux éléments sont toujours vérifiés de bout en bout — juste par la CI au lieu de ce bac à sable.
#[ignore]dhiddensteps-security::keyring_store::tests::set_get_delete_round_trip_against_the_real_vault — nécessite un vrai coffre-fort d'identifiants OS/session de bureau.hiddensteps-observation::linux::shortcuts::tests::grabs_and_ungrabs_a_real_shortcut — effectue un vrai XGrabKey à l'échelle de la session, ce qui serait perturbateur à exécuter automatiquement dans un environnement partagé.tests/ollama_live.rs de hiddensteps-llm-provider (2 tests) — nécessite une vraie instance Ollama en cours d'exécution. Les deux ont été réellement exécutés pendant le développement contre une vraie instance locale qwen3:0.6b (modèle à raisonnement hybride de 0,6 milliard de paramètres) et ont réussi en ~2 secondes combinées ; remplacez le modèle/URL via les variables d'environnement HIDDENSTEPS_TEST_OLLAMA_MODEL/HIDDENSTEPS_TEST_OLLAMA_URL pour une configuration différente.Les quatre sont de vrais tests, pas des vestiges — docs/roadmap/03-testing-strategy.md §2 établit exactement cette distinction entre la logique qui appartient derrière un mock dans la CI et l'intégration OS/session/service externe qui appartient à une vérification manuelle délibérée. Exécutez n'importe lequel avec cargo test -p <crate> -- --ignored (ajoutez <nom du test> pour n'en exécuter qu'un) sur une machine où cela est approprié.
PRAGMA foreign_keys = ONON DELETE CASCADE| 33 tests contre un vrai fichier SQLCipher : une mauvaise clé ne permet pas l'ouverture, la même clé rouvre correctement, la suppression totale efface toutes les tables y compris les plus récentes, l'aller-retour rekey fonctionne, le balayage TTL laisse les événements non expirés intacts, la suppression en cascade ne laisse aucun lien motif↔événement orphelin |
hiddensteps-redaction | Le moteur de rédaction (docs/design/05-privacy-model.md §4) : détecteurs regex+Luhn pour clés API/jetons/clés PEM/emails/NSS/numéros de carte bancaire, un détecteur de secrets ambigus basé sur l'entropie, et la politique d'abandon en cas d'incertitude | 30 tests, y compris des entrées délibérément adverses (secrets intégrés dans de la prose, quasi-secrets non secrets comme des SHA git, NSS sans tirets/espacés, numéros de carte avec chiffres ajoutés, jetons à haute entropie tout en une seule casse) |
hiddensteps-pipeline | Le pipeline d'événements (ADR-0006) : Classifier → Rédiger → Résumer, contrôle du niveau de confidentialité par type de signal, attribution du TTL en mode Deep | 8 tests couvrant les abandons déclenchés par la rédaction, les abandons par contrôle de niveau et la réussite de la synthèse |
hiddensteps-observation | ObservationSource (ADR-0005) + Linux : ActiveWindowSource (X11 GetInputFocus), FileOperationSource (inotify via notify), ClipboardMetadataSource (sélection X11, métadonnées uniquement), GlobalShortcutSource (X11 XGrabKey). Plus les fichiers de sources macOS/Windows (voir ci-dessous) | 10 des 11 tests s'exécutent contre de vrais backends dans cet environnement — un affichage X11 actif (DISPLAY=:0 de WSLg) et un vrai inotify, pas des mocks. 1 test (la vraie capture de GlobalShortcutSource) est #[ignore]d par conception |
hiddensteps-llm-provider | LlmProvider (ADR-0004) : client Ollama (avec un champ de requête think: Option<bool> pour les modèles à raisonnement hybride), un client compatible fil OpenAI (couvre OpenAI/Azure/OpenRouter/Together/Groq/DeepSeek/LocalAI), un client Anthropic Messages, et une auto-détection du runtime local. Chaque client définit un délai d'expiration de requête (build_http_client) pour qu'un serveur distant bloqué ne puisse pas bloquer un appel indéfiniment ; Ollama transmet max_tokens comme son options.num_predict imbriqué | 19 tests contre des serveurs mock wiremock (y compris une véritable vérification de déclenchement du délai d'expiration et que Ollama envoie réellement num_predict), plus 2 tests d'intégration réels Ollama (tests/ollama_live.rs, #[ignore]d — voir ci-dessous) qui ont trouvé et corrigé un vrai problème : la même invite prenait plus de deux minutes contre un vrai modèle local à raisonnement hybride avec think laissé à sa valeur par défaut, et quelques secondes avec think: Some(false) |
hiddensteps-patterns | Détection de motifs (correspondance de séquences n-grammes à fenêtre glissante) + graphe de flux de travail (graphe de transition avec poids d'arêtes) — couche 1 de l'ADR-0010 | 16 tests, y compris un analogue direct de l'exemple « observé 31 fois » de PROMPT.md et un test de régression vérifiant que les fenêtres qui se chevauchent sur une répétition continue ne sont pas comptées deux fois |
hiddensteps-recommendations | La couche 2 du moteur de recommandations (ADR-0010) : synthèse LLM avec un contrat d'invite JSON structuré, un validateur de contradiction narrative et une boucle de nouvelle tentative — surtout, les champs numériques (estimated_time_saved_minutes) ne sont jamais analysés depuis la sortie du LLM, uniquement calculés depuis la couche 1 | 23 tests, y compris nouvelle tentative sur JSON malformé, nouvelle tentative sur contradiction narrative (couvrant les nombres écrits en toutes lettres et chaque champ contrôlé par le LLM, pas seulement why), et extraction JSON sensible aux chaînes, contre un fournisseur de test scripté |
hiddensteps-privacy-engine | La passerelle de dispatch cloud (docs/design/03-data-flow-diagrams.md §5) et le versionnage du consentement (docs/design/05-privacy-model.md §5) ; PrivacyGatedProvider enveloppe n'importe quel LlmProvider pour que la passerelle ne puisse pas être contournée par le chemin d'appel normal | 13 tests, y compris que le contenu de niveau 4 est bloqué même avec tous les consentements accordés |
hiddensteps-plugin-host | L'hôte de plugins WASM (ADR-0009) : énumération fermée des capacités, validation des manifestes, un bac à sable basé sur wasmtime qui ne lie que les fonctions hôte des capacités accordées, plus un comptage de carburant et un ResourceLimiter mémoire bornant le CPU/mémoire d'une instance de plugin quelles que soient ses capacités — les deux axes que la section Déni de service de docs/research/06-threat-model.md nomme comme non couverts par la seule application des capacités (un module sans capacité peut quand même boucler ou faire croître sa mémoire indéfiniment). instantiate_from_manifest est le point d'entrée sûr : il force la validation du manifeste (la règle niveau-4-requis-pour-capture-d'écran) et refuse d'accorder quoi que ce soit que le manifeste n'a pas déclaré, avant que toute capacité n'atteigne le lieur — la simple tranche de capacités instantiate n'a aucun lien avec un manifeste du tout | 20 tests, y compris de véritables tentatives d'évasion de capacités : modules WAT écrits à la main compilés au moment du test, prouvant que l'import d'une capacité non accordée est réellement non résolu (l'instanciation échoue), pas simplement inutilisé ; plus un vrai module de boucle infinie et un module memory.grow non borné qui piègent au lieu de bloquer/épuiser la mémoire |
hiddensteps-enterprise-policy | Schéma de politique (docs/design/05-privacy-model.md §6) avec exactement deux réglages (plancher de niveau de confidentialité, liste blanche de fournisseurs) — aucun champ n'existe pour quoi que ce soit d'autre qu'une politique pourrait vouloir contraindre. Chargé depuis un fichier enterprise-policy.json dans le répertoire de données de l'application s'il est présent (un mécanisme réel, bien qu'intérimaire — le connecteur complet PolicyLoader de plugin que docs/design/08-plugin-architecture.md décrit n'est pas construit), persisté via la table enterprise_policy de hiddensteps-event-store, et réellement appliqué dans les commandes set_privacy_level/set_ai_provider de apps/desktop/src-tauri — les deux points de mutation par lesquels un choix de niveau/fournisseur est jamais écrit | 6 tests, y compris l'analyse d'un fichier de politique maximalement adverse avec cinq clés supplémentaires exclues par conception et la confirmation qu'aucune ne survit à l'analyse |
| Emplacement | Implémente | Vérifié comment |
|---|
../apps/desktop/ui | Interface React/TypeScript : OnboardingWizard (les 8 écrans, docs/ux/02), PrivacyDashboard (docs/ux/03), RecommendationCard (docs/ux/04), SettingsPage, DiagnosticsPage, câblés ensemble dans App.tsx — communiquant avec le cœur uniquement via un tauriBridge.ts typé | 50 tests via vitest + @testing-library/react contre un vrai rendu jsdom, y compris le contrôle d'étapes de l'assistant d'onboarding (pas d'avancement au-delà de la validation sans vérification réussie, pas de démarrage de l'observation sans cocher le consentement), l'affichage des erreurs sur chaque site d'appel de mutation, la bannière de reconsentement, la piste de preuves des recommandations et une passerelle d'accessibilité axe-core ; tsc -b vérifie les types proprement |
../apps/desktop/src-tauri | La coquille Tauri : ~21 commandes IPC (docs/design/09-api-specification.md) câblant chaque crate ci-dessus, plus une vraie boucle d'arrière-plan capture→pipeline→stockage→événement-UI pour Linux | Compile proprement sur Linux, macOS et Windows dans CI — pas dans ce bac à sable de développement spécifiquement (voir ../apps/desktop/README.md pour savoir pourquoi), mais la réserve « non vérifié » qui s'y trouvait a disparu : le premier vrai passage de la CI a trouvé et corrigé 3 vrais bugs (un dérivé Serialize manquant, un indicateur de fonctionnalité Cargo manquant, un fichier d'icône généré manquant) qu'aucune quantité de revue locale n'aurait attrapés |
core.github/workflows/ci.ymlCFDictionaryfind&CFStringCFDictionary<CFString, CFType>hiddensteps-observation/src/lib.rs — la première nécessite un artefact d'extension de navigateur séparé que ce dépôt ne contient pas ; la seconde (GlobalShortcutSource) est implémentée mais jamais démarrée automatiquement, car capturer une combinaison de touches à l'échelle de la session dans un bac à sable de développement partagé serait activement perturbateur.LlmProvider configuré ; elle a été testée contre un fournisseur de substitution scripté (de vraies assertions sur la logique de nouvelle tentative/validation). hiddensteps-llm-provider lui-même a maintenant une couverture réelle Ollama (voir ci-dessous) ; exécuter le contrat d'invite propre du synthétiseur contre un vrai modèle de bout en bout (plutôt que le client HTTP sous-jacent) est la prochaine étape naturelle, pas encore faite.get_diagnostics (la coquille Tauri) rapporte de vrais comptages d'événements/motifs/recommandations/journal d'audit et la vraie taille de fichier sur disque, mais pas l'utilisation GPU/CPU/mémoire, le statut des permissions OS d'observation ou le statut de mise à jour — la liste complète d'auto-diagnostics de PROMPT.md. Chaque composant d'interface qui affiche cela le dit explicitement plutôt que de montrer un « OK » fabriqué.