
HiddenSteps — una plataforma local-first de inteligencia de flujo de trabajo personal
Este es el complemento honesto y de estado actual del mapa de módulos objetivo de docs/design/02-system-architecture.md. Dice lo que realmente está construido, lo que está verificado contra un backend real en lugar de un mock, y lo que todavía falta de verdad — no lo que está planeado (eso está en docs/roadmap/01-implementation-roadmap.md).
Ejecuta cargo build --workspace && cargo test --workspace && cargo clippy --workspace --all-targets -- -D warnings desde la raíz del repositorio. A fecha de hoy: 12 crates, 193 pruebas que pasan, cero advertencias de clippy, cargo fmt --check limpio — 183 en los 11 crates que no necesitan pantalla ni servicio externo, más 10 en hiddensteps-observation que necesitan una pantalla X11 activa (verificadas donde existe una; ver esa fila). Cuatro pruebas están marcadas como #[ignore] por diseño (ver más abajo) y no se cuentan como fallos ni forman parte de las 193.
Además, fuera de crates/ (no forma parte del workspace raíz — ver por qué más abajo):
hiddensteps-event-store con similitud coseno calculada en Rust, en sustitución de la tabla virtual sqlite-vec de ADR-0007 (ver el comentario al principio de event-store/src/schema.sql) — cargar una extensión nativa de SQLite no era verificable en este entorno, y el propio ADR-0007 señala que en volúmenes realistas de un solo usuario, el comportamiento de sqlite-vec es búsqueda exacta por fuerza bruta. Misma semántica, sin riesgo de extensión nativa.hiddensteps-observation (src/macos/, src/windows/) son código fuente real y completo contra APIs de plataforma muy estables (CGWindowListCopyWindowInfo; GetForegroundWindow/GetWindowTextW/QueryFullProcessImageNameW) escritos sin tener disponible un toolchain de macOS/Windows — y ambos compilan limpio ahora, verificado por la matriz de trabajos de . El módulo de macOS necesitó primero una corrección real (los parámetros genéricos predeterminados sin tipo de no satisfacían el límite de trait de para una clave — corregido tipándolo explícitamente como ); Windows compiló limpio al primer intento.crates/crates/* es el workspace raíz de Cargo.toml y es completamente construible y probable en este entorno de desarrollo Linux con cero dependencias del sistema más allá de lo que cargo descarga. apps/desktop/src-tauri necesita webkit2gtk-4.1 (Linux) incluso para compilar, que este entorno no puede instalar (sin sudo sin contraseña, sin ruta funcional de nix/gestor de paquetes — confirmado por intento directo). Mantenerlo fuera del workspace significa que cargo build --workspace sigue estando 100% en verde aquí en lugar de permanentemente en rojo por un crate que nadie puede corregir en este sandbox. También necesita su propia tabla [workspace] vacía en su Cargo.toml por la misma razón — de lo contrario, Cargo intenta adjuntarlo de todos modos al workspace ancestro y falla con "current package believes it's in a workspace when it's not." apps/desktop/ui no tiene tal restricción y se verifica de la misma manera que el núcleo Rust. Ambas piezas están verificadas de extremo a extremo — solo que por CI en lugar de por este sandbox.
#[ignore]hiddensteps-security::keyring_store::tests::set_get_delete_round_trip_against_the_real_vault — necesita un almacén de credenciales real del sistema operativo/sesión de escritorio.hiddensteps-observation::linux::shortcuts::tests::grabs_and_ungrabs_a_real_shortcut — realiza un XGrabKey real a nivel de sesión, lo que sería disruptivo ejecutarlo automáticamente en un entorno compartido.tests/ollama_live.rs de hiddensteps-llm-provider (2 pruebas) — necesitan una instancia real de Ollama en ejecución. Ambas se ejecutaron realmente durante el desarrollo contra una instancia local real de qwen3:0.6b (modelo de razonamiento híbrido de 0.6B parámetros) y pasaron en ~2 segundos combinadas; anula el modelo/URL mediante las variables de entorno HIDDENSTEPS_TEST_OLLAMA_MODEL/HIDDENSTEPS_TEST_OLLAMA_URL para una configuración diferente.Las cuatro son pruebas reales, no vestigiales — docs/roadmap/03-testing-strategy.md §2 traza exactamente esta distinción entre la lógica que pertenece detrás de un mock en CI y la integración con el sistema operativo/la sesión/el servicio externo que pertenece a una verificación manual y deliberada. Ejecuta cualquiera de ellas con cargo test -p <crate> -- --ignored (añade <test name> para ejecutar solo una) en una máquina donde sea apropiado hacerlo.
| Crate | Implementa | Verificado cómo |
|---|
hiddensteps-domain | Tipos principales: PrivacyLevel/PrivacyState, EventSummary/SignalType, Pattern, Recommendation, AuditEntry y CapturedSignal — un tipo que estructuralmente no puede persistirse (sin Serialize), lo que aplica la regla de datos sin procesar de ADR-0006 a nivel de tipos | Pruebas unitarias: ida y vuelta/ordenación de niveles, control de TTL en modo profundo |
hiddensteps-security | SecretStore (ADR-0008): implementaciones reales de almacén del sistema operativo (KeyringSecretStore) + en memoria (para pruebas); generación de clave maestra CSPRNG (devuelta en un envoltorio zeroize::Zeroizing para que la clave se borre al soltar el objeto en lugar de quedar en memoria liberada); derivación de contraseña Argon2id para el modo portátil (PassphraseKey pone a cero su clave derivada al soltar el objeto, conservando la sal no secreta). hiddensteps-event-store también mantiene el texto SQL PRAGMA key/rekey, que contiene la clave, en Zeroizing | Pruebas unitarias contra el almacén en memoria y el KDF; la prueba de ida y vuelta con el almacén real está marcada como #[ignore] (ver más abajo) |
hiddensteps-event-store | SqlCipherEventStore (ADR-0003): el esquema completo de docs/design/07-database-schema.md, CRUD para el estado de privacidad, eventos, registro de auditoría, patrones, enlaces patrón↔evento, embeddings de patrones (ver nota más abajo), recomendaciones, configuración del proveedor LLM y ajustes genéricos, además de delete_all_data (transaccional; también ejecuta rekey para un "borrar todo" que sobrevive a un reinicio)/export_data/count_rows (diagnósticos)/delete_expired_events (la limpieza TTL del modo profundo, llamada desde el bucle periódico de recomendaciones de apps/desktop/src-tauri — ttl_expires_at se persistía desde v0.1.0 pero nada borraba una fila pasada esa fecha antes); aplicación de claves foráneas (PRAGMA foreign_keys = ON) para que el ON DELETE CASCADE de schema.sql en los enlaces patrón↔evento se ejecute de verdad | 33 pruebas contra un archivo SQLCipher real: una clave incorrecta no abre, la misma clave reabre correctamente, borrar todo limpia todas las tablas incluidas las más nuevas, rekey hace correctamente la ida y vuelta, la limpieza TTL deja intactos los eventos no caducados, el borrado en cascada no deja enlaces patrón↔evento huérfanos |
hiddensteps-redaction | El motor de redacción (docs/design/05-privacy-model.md §4): detectores regex+Luhn para claves API/tokens/claves PEM/emails/SSN/tarjetas de crédito, un detector de secretos ambiguos basado en entropía y la política de descartar ante la incertidumbre | 30 pruebas, incluidos inputs deliberadamente adversariales (secretos incrustados en prosa, no-secretos casi coincidentes como SHAs de git, SSN sin guiones o con espacios, números de tarjeta con dígitos de relleno, tokens de alta entropía con un solo tipo de caja) |
hiddensteps-pipeline | El pipeline de eventos (ADR-0006): Clasificar → Redactar → Resumir, control de nivel de privacidad por tipo de señal, asignación de TTL del modo profundo | 8 pruebas que cubren descartes provocados por la redacción, descartes por control de nivel y resúmenes exitosos |
hiddensteps-observation | ObservationSource (ADR-0005) + Linux: ActiveWindowSource (X11 GetInputFocus), FileOperationSource (inotify mediante notify), ClipboardMetadataSource (selección X11, solo metadatos), GlobalShortcutSource (X11 XGrabKey). Además archivos de fuentes para macOS/Windows (ver más abajo) | 10 de 11 pruebas se ejecutan contra backends reales en este entorno — una pantalla X11 activa (el DISPLAY=:0 de WSLg) e inotify real, no mocks. 1 prueba (la captura real de GlobalShortcutSource) está marcada como #[ignore] por diseño |
hiddensteps-llm-provider | LlmProvider (ADR-0004): cliente Ollama (con un campo de solicitud think: Option<bool> para modelos de razonamiento híbrido), un cliente compatible a nivel de protocolo con OpenAI (cubre OpenAI/Azure/OpenRouter/Together/Groq/DeepSeek/LocalAI), un cliente Anthropic Messages y auto-detección del runtime local. Cada cliente establece un tiempo de espera de solicitud (build_http_client) para que un remoto colgado no pueda bloquear una llamada para siempre; Ollama reenvía max_tokens como su anidado options.num_predict | 19 pruebas contra servidores mock wiremock (incluida una verificación real de que el tiempo de espera se dispara y de que Ollama realmente envía num_predict), más 2 pruebas de integración con Ollama real (tests/ollama_live.rs, marcadas como #[ignore] — ver más abajo) que encontraron y corrigieron un problema real: el mismo prompt tardó más de dos minutos contra un modelo local real de razonamiento híbrido con think en su valor predeterminado, y unos segundos con think: Some(false) |
hiddensteps-patterns | Detección de patrones (coincidencia de secuencias n-gram con ventana deslizante) + Grafo de flujo de trabajo (grafo de transición con pesos en las aristas) — Capa 1 de ADR-0010 | 16 pruebas, incluido un análogo directo del ejemplo "observed 31 times" del propio PROMPT.md y una prueba de regresión que verifica que las ventanas superpuestas sobre una repetición continua no se cuentan dos veces |
hiddensteps-recommendations | La Capa 2 del motor de recomendaciones (ADR-0010): síntesis LLM con un contrato de prompt JSON estructurado, un validador de contradicciones narrativas y un bucle de reintentos — lo crítico es que los campos numéricos (estimated_time_saved_minutes) nunca se parsean de la salida del LLM, solo se calculan a partir de la Capa 1 | 23 pruebas, incluidos reintentos por JSON malformado, reintentos por contradicción narrativa (que cubren números escritos con letras y todos los campos controlados por el LLM, no solo why) y extracción JSON consciente de cadenas, contra un proveedor de prueba con guion |
hiddensteps-privacy-engine | La compuerta de envío a la nube (docs/design/03-data-flow-diagrams.md §5) y el versionado de consentimiento (docs/design/05-privacy-model.md §5); PrivacyGatedProvider envuelve cualquier LlmProvider para que la compuerta no se pueda eludir mediante la ruta de llamada normal | 13 pruebas, incluida la de que el contenido de Nivel 4 se bloquea incluso con todos los consentimientos concedidos |
hiddensteps-plugin-host | El host de plugins WASM (ADR-0009): enumeración cerrada de capacidades, validación de manifiesto, un sandbox respaldado por wasmtime que enlaza solo las funciones de host de las capacidades concedidas, además de medición de combustible (fuel metering) y un ResourceLimiter de memoria que acota la CPU/memoria de una instancia de plugin sin importar qué capacidades tenga — los dos ejes que la sección de Denegación de servicio de docs/research/06-threat-model.md señala que la aplicación de capacidades por sí sola no puede abordar (un módulo sin capacidades aún puede quedarse en un bucle o crecer en memoria para siempre). instantiate_from_manifest es el punto de entrada seguro: fuerza la validación del manifiesto (la regla que exige el Nivel 4 para las capturas de pantalla) y rechaza conceder cualquier cosa que el manifiesto no haya declarado, antes de que cualquier capacidad llegue al enlazador — el slice de capacidades simple de instantiate no tiene tal vínculo con un manifiesto en absoluto | 20 pruebas, incluidos intentos reales de fuga de capacidades: módulos WAT escritos a mano compilados en tiempo de prueba, que demuestran que la importación de una capacidad no concedida está genuinamente sin resolver (la instanciación falla), no simplemente sin usar; además de un módulo real de bucle infinito y un módulo de memory.grow sin límite que generan un trap en lugar de colgarse o agotar la memoria |
hiddensteps-enterprise-policy | Esquema de políticas (docs/design/05-privacy-model.md §6) con exactamente dos controles (nivel mínimo de privacidad, lista de proveedores permitidos) — no existe ningún campo para cualquier otra cosa que una política pudiera querer restringir. Se carga desde un archivo enterprise-policy.json en el directorio de datos de la aplicación si está presente (un mecanismo real, aunque provisional — el conector completo PolicyLoader que describe docs/design/08-plugin-architecture.md no está construido), se persiste mediante la tabla enterprise_policy de hiddensteps-event-store, y se aplica de verdad en los comandos set_privacy_level/set_ai_provider de apps/desktop/src-tauri — los dos puntos de mutación desde los que se escribe una elección de nivel/proveedor | 6 pruebas, incluido el parseo de un archivo de políticas máximamente adversarial con cinco claves extra excluidas por diseño y la confirmación de que ninguna sobrevive al parseo |
| Ubicación | Implementa | Verificado cómo |
|---|
../apps/desktop/ui | UI React/TypeScript: OnboardingWizard (las 8 pantallas, docs/ux/02), PrivacyDashboard (docs/ux/03), RecommendationCard (docs/ux/04), SettingsPage, DiagnosticsPage, integrados en App.tsx — comunicándose con el núcleo solo a través de un tauriBridge.ts tipado | 50 pruebas mediante vitest + @testing-library/react contra renderizado jsdom real, incluido el control de pasos del asistente de incorporación (no se avanza más allá de la validación sin una comprobación exitosa, no se inicia la observación sin marcar la casilla de consentimiento), la presentación de errores en cada punto de llamada de mutación, el banner de re-consentimiento, el rastro de evidencia de las recomendaciones y una compuerta de accesibilidad axe-core; tsc -b comprueba tipos sin errores |
../apps/desktop/src-tauri | El shell de Tauri: ~21 comandos IPC (docs/design/09-api-specification.md) que conectan todos los crates anteriores, además de un bucle de fondo real de captura→pipeline→almacenamiento→eventos de UI para Linux | Compila limpio en Linux, macOS y Windows en CI — no específicamente en este sandbox de desarrollo (ver ../apps/desktop/README.md para saber por qué), pero la advertencia de "no verificado" que solía estar aquí ha desaparecido: la primera ejecución real de CI encontró y corrigió 3 errores reales (faltaba un derive Serialize, faltaba un flag de feature de Cargo, faltaba un archivo de icono generado) que ninguna cantidad de revisión local habría detectado |
core.github/workflows/ci.ymlCFDictionaryfind&CFStringCFDictionary<CFString, CFType>hiddensteps-observation/src/lib.rs — la primera necesita un artefacto de extensión de navegador separado que este repositorio no contiene; la segunda (GlobalShortcutSource) está implementada pero nunca se auto-inicia, porque capturar una combinación de teclas a nivel de sesión en un sandbox de desarrollo compartido sería activamente disruptivo.LlmProvider que esté configurado; se ha probado contra un proveedor sustituto con guion (afirmaciones reales sobre la lógica de reintento/validación). El propio hiddensteps-llm-provider ahora tiene cobertura con Ollama real (ver más abajo); ejecutar el contrato de prompt del propio sintetizador contra un modelo real de extremo a extremo (en lugar del cliente HTTP subyacente) es el siguiente paso natural, aún no hecho.get_diagnostics (el shell de Tauri) informa recuentos reales de eventos/patrones/recomendaciones/registro de auditoría y el tamaño real del archivo en disco, pero no el uso de GPU/CPU/memoria, el estado de permisos del sistema operativo para la observación ni el estado de actualización — la lista completa de autodiagnóstico de PROMPT.md. Cada componente de UI que renderiza esto lo dice explícitamente en lugar de mostrar un "OK" fabricado.