diff --git a/Cargo.lock b/Cargo.lock index 2cc8b5e..281b697 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -470,8 +470,8 @@ version = "0.2.0-beta.1" dependencies = [ "chanora_audio", "chanora_diagnostics", + "chanora_prefetch", "chanora_protocol", - "chanora_server_prefetch", "chanora_state", "chanora_storage", "rusqlite", @@ -489,6 +489,16 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "chanora_prefetch" +version = "0.2.0-beta.1" +dependencies = [ + "chanora_resolver", + "thiserror 2.0.18", + "tokio", + "tracing", +] + [[package]] name = "chanora_protocol" version = "0.2.0-beta.1" @@ -521,16 +531,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "chanora_server_prefetch" -version = "0.2.0-beta.1" -dependencies = [ - "chanora_resolver", - "thiserror 2.0.18", - "tokio", - "tracing", -] - [[package]] name = "chanora_state" version = "0.2.0-beta.1" diff --git a/Cargo.toml b/Cargo.toml index 64157ab..9a6ec0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ # crates/chanora_audio/ — capture, DSP, Opus, jitter, mixer # crates/chanora_storage/ — bookmarks, settings, identity refs # crates/chanora_diagnostics/ — logs, redaction, export -# crates/chanora_server_prefetch — server-resolution prefetch cache/policy +# crates/chanora_prefetch — server-resolution prefetch cache/policy # crates/chanora_bridge/ — Flutter/Rust typed DTOs + glue # # The Flutter app is not part of this Cargo workspace; it is owned by @@ -31,7 +31,7 @@ members = [ "crates/chanora_audio", "crates/chanora_storage", "crates/chanora_diagnostics", - "crates/chanora_server_prefetch", + "crates/chanora_prefetch", "crates/chanora_bridge", "crates/chanora_resolver", ] diff --git a/core/chanora_core/Cargo.toml b/core/chanora_core/Cargo.toml index 5827cd0..5722f35 100644 --- a/core/chanora_core/Cargo.toml +++ b/core/chanora_core/Cargo.toml @@ -15,7 +15,7 @@ chanora_state = { path = "../../crates/chanora_state" } chanora_audio = { path = "../../crates/chanora_audio" } chanora_storage = { path = "../../crates/chanora_storage" } chanora_diagnostics = { path = "../../crates/chanora_diagnostics" } -chanora_server_prefetch = { path = "../../crates/chanora_server_prefetch" } +chanora_prefetch = { path = "../../crates/chanora_prefetch" } thiserror.workspace = true tracing.workspace = true tokio = { version = "1", features = ["sync", "rt", "macros"] } @@ -23,6 +23,6 @@ tokio = { version = "1", features = ["sync", "rt", "macros"] } [dev-dependencies] # Used by integration tests to inspect the bookmark DB row layout # without going through the public repository API. -chanora_server_prefetch = { path = "../../crates/chanora_server_prefetch", features = ["test-support"] } +chanora_prefetch = { path = "../../crates/chanora_prefetch", features = ["test-support"] } rusqlite = { version = "0.32", features = ["bundled"] } tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread"] } diff --git a/core/chanora_core/src/lib.rs b/core/chanora_core/src/lib.rs index 670517d..884d4e7 100644 --- a/core/chanora_core/src/lib.rs +++ b/core/chanora_core/src/lib.rs @@ -46,7 +46,7 @@ use tokio::sync::{broadcast, oneshot, watch, Mutex}; use tokio::task::JoinHandle; use tracing::{info, warn}; -use chanora_server_prefetch::ServerPrefetcher; +use chanora_prefetch::ServerPrefetcher; use chanora_state::channel_join::{ self, AuthoritativeSource, ChannelId as JoinChannelId, ChannelJoinEvent, ChannelJoinState, ConnectionEpoch, JoinFailureKind, @@ -2506,9 +2506,7 @@ mod tests { .fail_next_prefetch_setup_for_test("resolver unavailable") .await; - let result = session - .prefetch_server(" Example.COM ".to_string()) - .await; + let result = session.prefetch_server(" Example.COM ".to_string()).await; assert!(result.is_ok()); } diff --git a/crates/chanora_server_prefetch/Cargo.toml b/crates/chanora_prefetch/Cargo.toml similarity index 93% rename from crates/chanora_server_prefetch/Cargo.toml rename to crates/chanora_prefetch/Cargo.toml index c2bf94c..15c913c 100644 --- a/crates/chanora_server_prefetch/Cargo.toml +++ b/crates/chanora_prefetch/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "chanora_server_prefetch" +name = "chanora_prefetch" description = "Chanora — server-address prefetch cache and policy built on chanora_resolver." version.workspace = true edition.workspace = true diff --git a/crates/chanora_server_prefetch/src/lib.rs b/crates/chanora_prefetch/src/lib.rs similarity index 96% rename from crates/chanora_server_prefetch/src/lib.rs rename to crates/chanora_prefetch/src/lib.rs index 8048696..17befaf 100644 --- a/crates/chanora_server_prefetch/src/lib.rs +++ b/crates/chanora_prefetch/src/lib.rs @@ -116,12 +116,12 @@ impl ServerPrefetcher { }; let cache = self.cache.clone(); tokio::spawn(async move { - info!(target: "chanora_server_prefetch", host = %normalized, "resolution prefetch started"); + info!(target: "chanora_prefetch", host = %normalized, "resolution prefetch started"); let result = resolve_socket(resolver, &normalized).await; match result { Ok(addr) => { info!( - target: "chanora_server_prefetch", + target: "chanora_prefetch", host = %normalized, resolved = %addr, "resolution prefetch result" @@ -131,7 +131,7 @@ impl ServerPrefetcher { } Err(err) => { warn!( - target: "chanora_server_prefetch", + target: "chanora_prefetch", host = %normalized, error = %err, "resolution prefetch failed" @@ -150,7 +150,7 @@ impl ServerPrefetcher { match resolved { Some(addr) => { info!( - target: "chanora_server_prefetch", + target: "chanora_prefetch", host = %host, resolved = %addr, "connect using prefetched resolution" @@ -158,7 +158,7 @@ impl ServerPrefetcher { Some(addr) } None => { - debug!(target: "chanora_server_prefetch", host = %host, "connect prefetch miss or stale"); + debug!(target: "chanora_prefetch", host = %host, "connect prefetch miss or stale"); None } } diff --git a/docs/architecture/sad.md b/docs/architecture/sad.md index 70a2d1a..44b8540 100644 --- a/docs/architecture/sad.md +++ b/docs/architecture/sad.md @@ -49,7 +49,7 @@ Chanora is a Flutter application with a Rust core. Flutter owns the user-facing | Storage | `crates/chanora_storage` | Bookmarks, identities, encrypted local data, platform keyring integration | Rust core, platform secure storage | | Diagnostics | `crates/chanora_diagnostics` | Redaction, log sink, export bundle, known-secret registry | Rust core, Flutter diagnostics UI | | Server resolver | `crates/chanora_resolver` | SRV/TSDNS/DNS fallback resolution | Rust core, prefetch crate | -| Server prefetch | `crates/chanora_server_prefetch`, Flutter `prefetch_debouncer.dart` | Invisible host-field resolution warming, TTL cache, generation safety | Resolver, Flutter connect UI, Rust core | +| Server prefetch | `crates/chanora_prefetch`, Flutter `prefetch_debouncer.dart` | Invisible host-field resolution warming, TTL cache, generation safety | Resolver, Flutter connect UI, Rust core | ## 5. Static Architecture View @@ -63,7 +63,7 @@ Flutter UI/widgets/services -> chanora_audio -> platform audio APIs / Opus / DSP -> chanora_storage -> platform secure storage / SQLite -> chanora_diagnostics - -> chanora_server_prefetch -> chanora_resolver -> network DNS/TSDNS + -> chanora_prefetch -> chanora_resolver -> network DNS/TSDNS ``` The bridge is the trust and type boundary between Flutter and Rust. Flutter must not directly depend on protocol-library internals. Rust core must not expose platform-specific storage or audio details to UI code except through stable DTOs and capability fields. diff --git a/docs/architecture/sdd.md b/docs/architecture/sdd.md index c966dd4..536d9c1 100644 --- a/docs/architecture/sdd.md +++ b/docs/architecture/sdd.md @@ -27,7 +27,7 @@ This Software Detailed Design defines the module-level design details needed for | SDD-MOD-011 Audio subsystem | `crates/chanora_audio/src/` | Audio capture/playback, DSP, Opus, PTT, mode stack, platform units | Audio subsystem | | SDD-MOD-012 Storage | `crates/chanora_storage/src/lib.rs` | Bookmarks, identity storage, encrypted local records, keyring abstraction | Storage | | SDD-MOD-013 Diagnostics | `crates/chanora_diagnostics/src/lib.rs` | Redaction, log sink, known-secret registry, export bundle | Diagnostics | -| SDD-MOD-014 Resolution and prefetch | `crates/chanora_resolver/src/lib.rs`, `crates/chanora_server_prefetch/src/lib.rs`, `prefetch_debouncer.dart` | SRV/TSDNS/DNS fallback and generation-safe resolution warming | Server resolver / prefetch | +| SDD-MOD-014 Resolution and prefetch | `crates/chanora_resolver/src/lib.rs`, `crates/chanora_prefetch/src/lib.rs`, `prefetch_debouncer.dart` | SRV/TSDNS/DNS fallback and generation-safe resolution warming | Server resolver / prefetch | | SDD-MOD-015 Build and release hooks | `.github/workflows/`, `tools/`, platform project files | CI, unsigned iOS build, benchmark advisory, platform smoke procedures | Release / platform architecture | ## 3. Bridge Boundary Design diff --git a/docs/implementation-status-2026-05-28.md b/docs/implementation-status-2026-05-28.md index 1ba862d..2b79811 100644 --- a/docs/implementation-status-2026-05-28.md +++ b/docs/implementation-status-2026-05-28.md @@ -27,7 +27,7 @@ | Storage (secrets) | `IdentityFileStore` with platform keyring (Linux Secret Service, macOS Keychain, Windows Credential Manager, iOS Keychain); file fallback with 0600 perms | | Diagnostics | `chanora_diagnostics` — `Redactor` (IP/host/email/token/path/secret scrubbing), `InMemoryLogSink`, `DiagnosticExport` JSON bundle, `KnownSecretRegistry`, panic hook | | Server address resolution | `chanora_resolver` — SRV/TSDNS/DNS fallback | -| Server prefetch | `chanora_server_prefetch` crate + `prefetch_debouncer.dart` — invisible host-field prefetch, TTL cache, generation-safe | +| Server prefetch | `chanora_prefetch` crate + `prefetch_debouncer.dart` — invisible host-field prefetch, TTL cache, generation-safe | | Android platform | `android_voice_unit.rs`, `android_permissions_service.dart`, `MODE_IN_COMMUNICATION` routing, foreground service (`flutter_foreground_task`) | | iOS platform | `ios_voice_unit.rs`, `ios_raw_unit.rs`, `ios_permissions_service.dart`, `AVAudioSession` integration, `audio_session` package | | Permission UX | `permission_state_banner.dart`, pre-request explainers | diff --git a/docs/security/dependency-and-supply-chain-report.md b/docs/security/dependency-and-supply-chain-report.md index a11313c..29ca233 100644 --- a/docs/security/dependency-and-supply-chain-report.md +++ b/docs/security/dependency-and-supply-chain-report.md @@ -22,7 +22,7 @@ This report summarizes the current dependency and supply-chain controls visible | Area | Examples from current repository | DV status | |---|---|---| -| Rust workspace crates | `chanora_protocol`, `chanora_audio`, `chanora_storage`, `chanora_diagnostics`, `chanora_bridge`, `chanora_resolver`, `chanora_server_prefetch`, `chanora_state`, `chanora_core` | In workspace and covered by CI commands | +| Rust workspace crates | `chanora_protocol`, `chanora_audio`, `chanora_storage`, `chanora_diagnostics`, `chanora_bridge`, `chanora_resolver`, `chanora_prefetch`, `chanora_state`, `chanora_core` | In workspace and covered by CI commands | | Flutter app dependencies | `flutter_rust_bridge`, `audio_session`, `flutter_foreground_task`, `package_info_plus`, `share_plus`, `shared_preferences` | Covered by Flutter dependency resolution and license inventory job | | Native/audio dependencies | Opus, platform audio stacks, Android/iOS audio services | Require platform build and license review evidence | | Patched Rust dependency | `cmake` patched to a pinned git revision for Android build support | Requires DEC-032 tracking and periodic reevaluation | diff --git a/docs/security/license-inventory.md b/docs/security/license-inventory.md index d3544f4..f8a40ee 100644 --- a/docs/security/license-inventory.md +++ b/docs/security/license-inventory.md @@ -292,9 +292,9 @@ those terms. | chanora_audio | 0.2.0-beta.1 | `Apache License 2.0` | | | chanora_bridge | 0.2.0-beta.1 | `Apache License 2.0` | | | chanora_diagnostics | 0.2.0-beta.1 | `Apache License 2.0` | | +| chanora_prefetch | 0.2.0-beta.1 | `Apache License 2.0` | | | chanora_protocol | 0.2.0-beta.1 | `Apache License 2.0` | | | chanora_resolver | 0.1.0 | `Apache License 2.0` | — | -| chanora_server_prefetch | 0.2.0-beta.1 | `Apache License 2.0` | | | chanora_state | 0.2.0-beta.1 | `Apache License 2.0` | | | chanora_storage | 0.2.0-beta.1 | `Apache License 2.0` | | | alsa | 0.11.0 | `Apache License 2.0` | | diff --git a/docs/superpowers/plans/2026-05-28-chanora-server-prefetch-crate.md b/docs/superpowers/plans/2026-05-28-chanora-server-prefetch-crate.md index 7e3359a..ebbcf4a 100644 --- a/docs/superpowers/plans/2026-05-28-chanora-server-prefetch-crate.md +++ b/docs/superpowers/plans/2026-05-28-chanora-server-prefetch-crate.md @@ -2,9 +2,9 @@ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. -**Goal:** Move server-resolution prefetch policy from `chanora_core` into a focused crate named `chanora_server_prefetch` without changing Flutter APIs, resolver behavior, protocol dialing behavior, or Android connect UX. +**Goal:** Move server-resolution prefetch policy from `chanora_core` into a focused crate named `chanora_prefetch` without changing Flutter APIs, resolver behavior, protocol dialing behavior, or Android connect UX. -**Architecture:** Add `crates/chanora_server_prefetch` as a workspace member. The new crate owns normalization, single-entry TTL cache, generation rejection, resolver-backed async warming, and fresh exact-match lookup. `chanora_core` keeps the trust boundary for `ConnectConfig.resolved_address`, using the prefetcher only to populate one-time dial config while keeping stored/reconnect config sanitized. +**Architecture:** Add `crates/chanora_prefetch` as a workspace member. The new crate owns normalization, single-entry TTL cache, generation rejection, resolver-backed async warming, and fresh exact-match lookup. `chanora_core` keeps the trust boundary for `ConnectConfig.resolved_address`, using the prefetcher only to populate one-time dial config while keeping stored/reconnect config sanitized. **Tech Stack:** Rust workspace, `tokio`, `tracing`, `thiserror`, `chanora_resolver`, `chanora_core`, `chanora_protocol`, Flutter Android smoke via ADB. @@ -12,28 +12,28 @@ ## File Structure -- Create `crates/chanora_server_prefetch/Cargo.toml`: package metadata and dependencies. -- Create `crates/chanora_server_prefetch/src/lib.rs`: public `ServerPrefetcher`, public `ServerPrefetchError`, internal cache entry/state, resolver-backed prefetch logic, and unit tests. -- Modify `Cargo.toml`: add `crates/chanora_server_prefetch` to workspace members and update the workspace layout comment. -- Modify `core/chanora_core/Cargo.toml`: replace the direct `chanora_resolver` dependency with `chanora_server_prefetch`. +- Create `crates/chanora_prefetch/Cargo.toml`: package metadata and dependencies. +- Create `crates/chanora_prefetch/src/lib.rs`: public `ServerPrefetcher`, public `ServerPrefetchError`, internal cache entry/state, resolver-backed prefetch logic, and unit tests. +- Modify `Cargo.toml`: add `crates/chanora_prefetch` to workspace members and update the workspace layout comment. +- Modify `core/chanora_core/Cargo.toml`: replace the direct `chanora_resolver` dependency with `chanora_prefetch`. - Modify `core/chanora_core/src/lib.rs`: remove private prefetch cache/resolver helpers, add `ServerPrefetcher`, delegate `prefetch_server_resolution`, and keep connect config sanitization tests. - Modify `Cargo.lock`: generated by `cargo test`/`cargo check` after adding the crate. --- -### Task 1: Add `chanora_server_prefetch` Crate With Cache Policy Tests +### Task 1: Add `chanora_prefetch` Crate With Cache Policy Tests **Files:** - Modify: `Cargo.toml` -- Create: `crates/chanora_server_prefetch/Cargo.toml` -- Create: `crates/chanora_server_prefetch/src/lib.rs` +- Create: `crates/chanora_prefetch/Cargo.toml` +- Create: `crates/chanora_prefetch/src/lib.rs` - [ ] **Step 1: Add the workspace member and package files** In top-level `Cargo.toml`, update the layout comment and members: ```toml -# crates/chanora_server_prefetch — server-resolution prefetch cache/policy +# crates/chanora_prefetch — server-resolution prefetch cache/policy # crates/chanora_bridge/ — Flutter/Rust typed DTOs + glue ``` @@ -45,17 +45,17 @@ members = [ "crates/chanora_audio", "crates/chanora_storage", "crates/chanora_diagnostics", - "crates/chanora_server_prefetch", + "crates/chanora_prefetch", "crates/chanora_bridge", "crates/chanora_resolver", ] ``` -Create `crates/chanora_server_prefetch/Cargo.toml`: +Create `crates/chanora_prefetch/Cargo.toml`: ```toml [package] -name = "chanora_server_prefetch" +name = "chanora_prefetch" description = "Chanora — server-address prefetch cache and policy built on chanora_resolver." version.workspace = true edition.workspace = true @@ -75,7 +75,7 @@ tokio = { version = "1", features = ["sync", "rt", "macros"] } test-support = [] ``` -Create `crates/chanora_server_prefetch/src/lib.rs` with the initial crate implementation and tests: +Create `crates/chanora_prefetch/src/lib.rs` with the initial crate implementation and tests: ```rust //! Server-address prefetch cache and policy for Chanora. @@ -189,13 +189,13 @@ impl ServerPrefetcher { }; let cache = self.cache.clone(); tokio::spawn(async move { - info!(target: "chanora_server_prefetch", host = %normalized, "resolution prefetch started"); + info!(target: "chanora_prefetch", host = %normalized, "resolution prefetch started"); let result = resolve_socket(&normalized).await; let mut guard = cache.lock().await; match result { Ok(addr) => { info!( - target: "chanora_server_prefetch", + target: "chanora_prefetch", host = %normalized, resolved = %addr, "resolution prefetch result" @@ -204,7 +204,7 @@ impl ServerPrefetcher { } Err(err) => { warn!( - target: "chanora_server_prefetch", + target: "chanora_prefetch", host = %normalized, error = %err, "resolution prefetch failed" @@ -224,7 +224,7 @@ impl ServerPrefetcher { match resolved { Some(addr) => { info!( - target: "chanora_server_prefetch", + target: "chanora_prefetch", host = %host, resolved = %addr, "connect using prefetched resolution" @@ -232,7 +232,7 @@ impl ServerPrefetcher { Some(addr) } None => { - info!(target: "chanora_server_prefetch", host = %host, "connect prefetch miss or stale"); + info!(target: "chanora_prefetch", host = %host, "connect prefetch miss or stale"); None } } @@ -350,14 +350,14 @@ mod tests { - [ ] **Step 2: Run new crate tests** -Run: `cargo test -p chanora_server_prefetch --lib` +Run: `cargo test -p chanora_prefetch --lib` Expected: the new crate compiles and all 5 tests pass. - [ ] **Step 3: Commit Task 1** ```bash -git add Cargo.toml Cargo.lock crates/chanora_server_prefetch +git add Cargo.toml Cargo.lock crates/chanora_prefetch git commit -m "feat(prefetch): add server prefetch crate" ``` @@ -380,7 +380,7 @@ chanora_resolver = { path = "../../crates/chanora_resolver" } with: ```toml -chanora_server_prefetch = { path = "../../crates/chanora_server_prefetch" } +chanora_prefetch = { path = "../../crates/chanora_prefetch" } ``` - [ ] **Step 2: Remove private prefetch cache implementation from core** @@ -406,7 +406,7 @@ async fn resolve_prefetch_socket(host: &str) -> Result