Merge pull request #12 from EdisonJwa/chore/rename-prefetch-crate-pr

chore(prefetch): rename server prefetch crate
This commit is contained in:
Edison Jwa
2026-06-02 14:12:24 +09:00
committed by GitHub
15 changed files with 66 additions and 68 deletions
Generated
+11 -11
View File
@@ -470,8 +470,8 @@ version = "0.2.0-beta.1"
dependencies = [ dependencies = [
"chanora_audio", "chanora_audio",
"chanora_diagnostics", "chanora_diagnostics",
"chanora_prefetch",
"chanora_protocol", "chanora_protocol",
"chanora_server_prefetch",
"chanora_state", "chanora_state",
"chanora_storage", "chanora_storage",
"rusqlite", "rusqlite",
@@ -489,6 +489,16 @@ dependencies = [
"tracing-subscriber", "tracing-subscriber",
] ]
[[package]]
name = "chanora_prefetch"
version = "0.2.0-beta.1"
dependencies = [
"chanora_resolver",
"thiserror 2.0.18",
"tokio",
"tracing",
]
[[package]] [[package]]
name = "chanora_protocol" name = "chanora_protocol"
version = "0.2.0-beta.1" version = "0.2.0-beta.1"
@@ -521,16 +531,6 @@ dependencies = [
"tracing-subscriber", "tracing-subscriber",
] ]
[[package]]
name = "chanora_server_prefetch"
version = "0.2.0-beta.1"
dependencies = [
"chanora_resolver",
"thiserror 2.0.18",
"tokio",
"tracing",
]
[[package]] [[package]]
name = "chanora_state" name = "chanora_state"
version = "0.2.0-beta.1" version = "0.2.0-beta.1"
+2 -2
View File
@@ -12,7 +12,7 @@
# crates/chanora_audio/ — capture, DSP, Opus, jitter, mixer # crates/chanora_audio/ — capture, DSP, Opus, jitter, mixer
# crates/chanora_storage/ — bookmarks, settings, identity refs # crates/chanora_storage/ — bookmarks, settings, identity refs
# crates/chanora_diagnostics/ — logs, redaction, export # 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 # crates/chanora_bridge/ — Flutter/Rust typed DTOs + glue
# #
# The Flutter app is not part of this Cargo workspace; it is owned by # The Flutter app is not part of this Cargo workspace; it is owned by
@@ -31,7 +31,7 @@ members = [
"crates/chanora_audio", "crates/chanora_audio",
"crates/chanora_storage", "crates/chanora_storage",
"crates/chanora_diagnostics", "crates/chanora_diagnostics",
"crates/chanora_server_prefetch", "crates/chanora_prefetch",
"crates/chanora_bridge", "crates/chanora_bridge",
"crates/chanora_resolver", "crates/chanora_resolver",
] ]
+2 -2
View File
@@ -15,7 +15,7 @@ chanora_state = { path = "../../crates/chanora_state" }
chanora_audio = { path = "../../crates/chanora_audio" } chanora_audio = { path = "../../crates/chanora_audio" }
chanora_storage = { path = "../../crates/chanora_storage" } chanora_storage = { path = "../../crates/chanora_storage" }
chanora_diagnostics = { path = "../../crates/chanora_diagnostics" } chanora_diagnostics = { path = "../../crates/chanora_diagnostics" }
chanora_server_prefetch = { path = "../../crates/chanora_server_prefetch" } chanora_prefetch = { path = "../../crates/chanora_prefetch" }
thiserror.workspace = true thiserror.workspace = true
tracing.workspace = true tracing.workspace = true
tokio = { version = "1", features = ["sync", "rt", "macros"] } tokio = { version = "1", features = ["sync", "rt", "macros"] }
@@ -23,6 +23,6 @@ tokio = { version = "1", features = ["sync", "rt", "macros"] }
[dev-dependencies] [dev-dependencies]
# Used by integration tests to inspect the bookmark DB row layout # Used by integration tests to inspect the bookmark DB row layout
# without going through the public repository API. # 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"] } rusqlite = { version = "0.32", features = ["bundled"] }
tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread"] } tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread"] }
+2 -4
View File
@@ -46,7 +46,7 @@ use tokio::sync::{broadcast, oneshot, watch, Mutex};
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use tracing::{info, warn}; use tracing::{info, warn};
use chanora_server_prefetch::ServerPrefetcher; use chanora_prefetch::ServerPrefetcher;
use chanora_state::channel_join::{ use chanora_state::channel_join::{
self, AuthoritativeSource, ChannelId as JoinChannelId, ChannelJoinEvent, ChannelJoinState, self, AuthoritativeSource, ChannelId as JoinChannelId, ChannelJoinEvent, ChannelJoinState,
ConnectionEpoch, JoinFailureKind, ConnectionEpoch, JoinFailureKind,
@@ -2506,9 +2506,7 @@ mod tests {
.fail_next_prefetch_setup_for_test("resolver unavailable") .fail_next_prefetch_setup_for_test("resolver unavailable")
.await; .await;
let result = session let result = session.prefetch_server(" Example.COM ".to_string()).await;
.prefetch_server(" Example.COM ".to_string())
.await;
assert!(result.is_ok()); assert!(result.is_ok());
} }
@@ -1,5 +1,5 @@
[package] [package]
name = "chanora_server_prefetch" name = "chanora_prefetch"
description = "Chanora — server-address prefetch cache and policy built on chanora_resolver." description = "Chanora — server-address prefetch cache and policy built on chanora_resolver."
version.workspace = true version.workspace = true
edition.workspace = true edition.workspace = true
@@ -116,12 +116,12 @@ impl ServerPrefetcher {
}; };
let cache = self.cache.clone(); let cache = self.cache.clone();
tokio::spawn(async move { 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; let result = resolve_socket(resolver, &normalized).await;
match result { match result {
Ok(addr) => { Ok(addr) => {
info!( info!(
target: "chanora_server_prefetch", target: "chanora_prefetch",
host = %normalized, host = %normalized,
resolved = %addr, resolved = %addr,
"resolution prefetch result" "resolution prefetch result"
@@ -131,7 +131,7 @@ impl ServerPrefetcher {
} }
Err(err) => { Err(err) => {
warn!( warn!(
target: "chanora_server_prefetch", target: "chanora_prefetch",
host = %normalized, host = %normalized,
error = %err, error = %err,
"resolution prefetch failed" "resolution prefetch failed"
@@ -150,7 +150,7 @@ impl ServerPrefetcher {
match resolved { match resolved {
Some(addr) => { Some(addr) => {
info!( info!(
target: "chanora_server_prefetch", target: "chanora_prefetch",
host = %host, host = %host,
resolved = %addr, resolved = %addr,
"connect using prefetched resolution" "connect using prefetched resolution"
@@ -158,7 +158,7 @@ impl ServerPrefetcher {
Some(addr) Some(addr)
} }
None => { 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 None
} }
} }
+2 -2
View File
@@ -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 | | 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 | | 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 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 ## 5. Static Architecture View
@@ -63,7 +63,7 @@ Flutter UI/widgets/services
-> chanora_audio -> platform audio APIs / Opus / DSP -> chanora_audio -> platform audio APIs / Opus / DSP
-> chanora_storage -> platform secure storage / SQLite -> chanora_storage -> platform secure storage / SQLite
-> chanora_diagnostics -> 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. 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.
+1 -1
View File
@@ -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-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-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-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 | | 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 ## 3. Bridge Boundary Design
+1 -1
View File
@@ -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 | | 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 | | 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 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`) | | 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 | | 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 | | Permission UX | `permission_state_banner.dart`, pre-request explainers |
@@ -22,7 +22,7 @@ This report summarizes the current dependency and supply-chain controls visible
| Area | Examples from current repository | DV status | | 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 | | 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 | | 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 | | Patched Rust dependency | `cmake` patched to a pinned git revision for Android build support | Requires DEC-032 tracking and periodic reevaluation |
+1 -1
View File
@@ -292,9 +292,9 @@ those terms.
| chanora_audio | 0.2.0-beta.1 | `Apache License 2.0` | <https://github.com/anomalyco/opencode> | | chanora_audio | 0.2.0-beta.1 | `Apache License 2.0` | <https://github.com/anomalyco/opencode> |
| chanora_bridge | 0.2.0-beta.1 | `Apache License 2.0` | <https://github.com/anomalyco/opencode> | | chanora_bridge | 0.2.0-beta.1 | `Apache License 2.0` | <https://github.com/anomalyco/opencode> |
| chanora_diagnostics | 0.2.0-beta.1 | `Apache License 2.0` | <https://github.com/anomalyco/opencode> | | chanora_diagnostics | 0.2.0-beta.1 | `Apache License 2.0` | <https://github.com/anomalyco/opencode> |
| chanora_prefetch | 0.2.0-beta.1 | `Apache License 2.0` | <https://github.com/anomalyco/opencode> |
| chanora_protocol | 0.2.0-beta.1 | `Apache License 2.0` | <https://github.com/anomalyco/opencode> | | chanora_protocol | 0.2.0-beta.1 | `Apache License 2.0` | <https://github.com/anomalyco/opencode> |
| chanora_resolver | 0.1.0 | `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` | <https://github.com/anomalyco/opencode> |
| chanora_state | 0.2.0-beta.1 | `Apache License 2.0` | <https://github.com/anomalyco/opencode> | | chanora_state | 0.2.0-beta.1 | `Apache License 2.0` | <https://github.com/anomalyco/opencode> |
| chanora_storage | 0.2.0-beta.1 | `Apache License 2.0` | <https://github.com/anomalyco/opencode> | | chanora_storage | 0.2.0-beta.1 | `Apache License 2.0` | <https://github.com/anomalyco/opencode> |
| alsa | 0.11.0 | `Apache License 2.0` | <https://github.com/diwic/alsa-rs> | | alsa | 0.11.0 | `Apache License 2.0` | <https://github.com/diwic/alsa-rs> |
@@ -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. > **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. **Tech Stack:** Rust workspace, `tokio`, `tracing`, `thiserror`, `chanora_resolver`, `chanora_core`, `chanora_protocol`, Flutter Android smoke via ADB.
@@ -12,28 +12,28 @@
## File Structure ## File Structure
- Create `crates/chanora_server_prefetch/Cargo.toml`: package metadata and dependencies. - Create `crates/chanora_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. - 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_server_prefetch` to workspace members and update the workspace layout comment. - 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_server_prefetch`. - 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 `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. - 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:** **Files:**
- Modify: `Cargo.toml` - Modify: `Cargo.toml`
- Create: `crates/chanora_server_prefetch/Cargo.toml` - Create: `crates/chanora_prefetch/Cargo.toml`
- Create: `crates/chanora_server_prefetch/src/lib.rs` - Create: `crates/chanora_prefetch/src/lib.rs`
- [ ] **Step 1: Add the workspace member and package files** - [ ] **Step 1: Add the workspace member and package files**
In top-level `Cargo.toml`, update the layout comment and members: In top-level `Cargo.toml`, update the layout comment and members:
```toml ```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 # crates/chanora_bridge/ — Flutter/Rust typed DTOs + glue
``` ```
@@ -45,17 +45,17 @@ members = [
"crates/chanora_audio", "crates/chanora_audio",
"crates/chanora_storage", "crates/chanora_storage",
"crates/chanora_diagnostics", "crates/chanora_diagnostics",
"crates/chanora_server_prefetch", "crates/chanora_prefetch",
"crates/chanora_bridge", "crates/chanora_bridge",
"crates/chanora_resolver", "crates/chanora_resolver",
] ]
``` ```
Create `crates/chanora_server_prefetch/Cargo.toml`: Create `crates/chanora_prefetch/Cargo.toml`:
```toml ```toml
[package] [package]
name = "chanora_server_prefetch" name = "chanora_prefetch"
description = "Chanora — server-address prefetch cache and policy built on chanora_resolver." description = "Chanora — server-address prefetch cache and policy built on chanora_resolver."
version.workspace = true version.workspace = true
edition.workspace = true edition.workspace = true
@@ -75,7 +75,7 @@ tokio = { version = "1", features = ["sync", "rt", "macros"] }
test-support = [] 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 ```rust
//! Server-address prefetch cache and policy for Chanora. //! Server-address prefetch cache and policy for Chanora.
@@ -189,13 +189,13 @@ impl ServerPrefetcher {
}; };
let cache = self.cache.clone(); let cache = self.cache.clone();
tokio::spawn(async move { 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 result = resolve_socket(&normalized).await;
let mut guard = cache.lock().await; let mut guard = cache.lock().await;
match result { match result {
Ok(addr) => { Ok(addr) => {
info!( info!(
target: "chanora_server_prefetch", target: "chanora_prefetch",
host = %normalized, host = %normalized,
resolved = %addr, resolved = %addr,
"resolution prefetch result" "resolution prefetch result"
@@ -204,7 +204,7 @@ impl ServerPrefetcher {
} }
Err(err) => { Err(err) => {
warn!( warn!(
target: "chanora_server_prefetch", target: "chanora_prefetch",
host = %normalized, host = %normalized,
error = %err, error = %err,
"resolution prefetch failed" "resolution prefetch failed"
@@ -224,7 +224,7 @@ impl ServerPrefetcher {
match resolved { match resolved {
Some(addr) => { Some(addr) => {
info!( info!(
target: "chanora_server_prefetch", target: "chanora_prefetch",
host = %host, host = %host,
resolved = %addr, resolved = %addr,
"connect using prefetched resolution" "connect using prefetched resolution"
@@ -232,7 +232,7 @@ impl ServerPrefetcher {
Some(addr) Some(addr)
} }
None => { 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 None
} }
} }
@@ -350,14 +350,14 @@ mod tests {
- [ ] **Step 2: Run new crate 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. Expected: the new crate compiles and all 5 tests pass.
- [ ] **Step 3: Commit Task 1** - [ ] **Step 3: Commit Task 1**
```bash ```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" git commit -m "feat(prefetch): add server prefetch crate"
``` ```
@@ -380,7 +380,7 @@ chanora_resolver = { path = "../../crates/chanora_resolver" }
with: with:
```toml ```toml
chanora_server_prefetch = { path = "../../crates/chanora_server_prefetch" } chanora_prefetch = { path = "../../crates/chanora_prefetch" }
``` ```
- [ ] **Step 2: Remove private prefetch cache implementation from core** - [ ] **Step 2: Remove private prefetch cache implementation from core**
@@ -406,7 +406,7 @@ async fn resolve_prefetch_socket(host: &str) -> Result<std::net::SocketAddr, Cor
Add this import near the other crate imports: Add this import near the other crate imports:
```rust ```rust
use chanora_server_prefetch::ServerPrefetcher; use chanora_prefetch::ServerPrefetcher;
``` ```
- [ ] **Step 3: Replace the session field and constructor initialization** - [ ] **Step 3: Replace the session field and constructor initialization**
@@ -478,7 +478,7 @@ connect_config_without_prefetched_resolution_clears_only_resolved_address
connect_config_preparation_keeps_prefetched_address_out_of_stored_config connect_config_preparation_keeps_prefetched_address_out_of_stored_config
``` ```
Replace any direct access to `session.resolution_prefetch` with calls to public test-support methods on `ServerPrefetcher`. In `crates/chanora_server_prefetch/src/lib.rs`, keep these methods gated with `#[cfg(any(test, feature = "test-support"))]`: Replace any direct access to `session.resolution_prefetch` with calls to public test-support methods on `ServerPrefetcher`. In `crates/chanora_prefetch/src/lib.rs`, keep these methods gated with `#[cfg(any(test, feature = "test-support"))]`:
```rust ```rust
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
@@ -502,7 +502,7 @@ Enable the feature for `chanora_core` tests by adding this dev-dependency in `co
```toml ```toml
[dev-dependencies] [dev-dependencies]
chanora_server_prefetch = { path = "../../crates/chanora_server_prefetch", features = ["test-support"] } chanora_prefetch = { path = "../../crates/chanora_prefetch", features = ["test-support"] }
``` ```
Then core test setup should look like: Then core test setup should look like:
@@ -524,7 +524,7 @@ Expected: all core lib tests pass.
- [ ] **Step 7: Commit Task 2** - [ ] **Step 7: Commit Task 2**
```bash ```bash
git add Cargo.toml Cargo.lock core/chanora_core/Cargo.toml core/chanora_core/src/lib.rs crates/chanora_server_prefetch git add Cargo.toml Cargo.lock core/chanora_core/Cargo.toml core/chanora_core/src/lib.rs crates/chanora_prefetch
git commit -m "refactor(core): use server prefetch crate" git commit -m "refactor(core): use server prefetch crate"
``` ```
@@ -538,7 +538,7 @@ git commit -m "refactor(core): use server prefetch crate"
- [ ] **Step 1: Remove core tests moved to the prefetch crate** - [ ] **Step 1: Remove core tests moved to the prefetch crate**
Delete these tests from `core/chanora_core/src/lib.rs` because they now belong in `chanora_server_prefetch`: Delete these tests from `core/chanora_core/src/lib.rs` because they now belong in `chanora_prefetch`:
```rust ```rust
resolution_prefetch_cache_returns_fresh_exact_match resolution_prefetch_cache_returns_fresh_exact_match
@@ -564,7 +564,7 @@ Expected: no diff. If there is a diff, revert only accidental protocol edits by
- [ ] **Step 3: Run combined Rust tests** - [ ] **Step 3: Run combined Rust tests**
Run: `cargo test -p chanora_server_prefetch -p chanora_core -p chanora_protocol --lib` Run: `cargo test -p chanora_prefetch -p chanora_core -p chanora_protocol --lib`
Expected: all tests pass. Expected: all tests pass.
@@ -584,7 +584,7 @@ git commit -m "test(core): keep prefetch tests at crate boundary"
- [ ] **Step 1: Run full focused Rust verification** - [ ] **Step 1: Run full focused Rust verification**
Run: `cargo test -p chanora_resolver -p chanora_server_prefetch -p chanora_protocol -p chanora_core --lib` Run: `cargo test -p chanora_resolver -p chanora_prefetch -p chanora_protocol -p chanora_core --lib`
Expected: all tests pass. Expected: all tests pass.
@@ -684,6 +684,6 @@ Expected: only unrelated untracked `config.json` remains, unless the user has ad
## Self-Review ## Self-Review
- Spec coverage: the plan adds `chanora_server_prefetch`, moves cache policy and resolver-backed warming there, keeps core as trust boundary, preserves Flutter/protocol behavior, and includes Android connect smoke verification. - Spec coverage: the plan adds `chanora_prefetch`, moves cache policy and resolver-backed warming there, keeps core as trust boundary, preserves Flutter/protocol behavior, and includes Android connect smoke verification.
- Placeholder scan: no `TBD`, `TODO`, or unspecified edge handling remains. - Placeholder scan: no `TBD`, `TODO`, or unspecified edge handling remains.
- Type consistency: the plan uses `ServerPrefetcher`, `ServerPrefetchError`, `prefetch`, and `fresh_match` consistently across crate and core tasks. - Type consistency: the plan uses `ServerPrefetcher`, `ServerPrefetchError`, `prefetch`, and `fresh_match` consistently across crate and core tasks.
@@ -4,7 +4,7 @@ Date: 2026-05-28
## Goal ## Goal
Move server-resolution prefetch policy out of `chanora_core` into a focused Rust crate named `chanora_server_prefetch`, without changing connection behavior, Flutter APIs, or protocol dialing semantics. Move server-resolution prefetch policy out of `chanora_core` into a focused Rust crate named `chanora_prefetch`, without changing connection behavior, Flutter APIs, or protocol dialing semantics.
## Non-Goals ## Non-Goals
@@ -16,7 +16,7 @@ Move server-resolution prefetch policy out of `chanora_core` into a focused Rust
## Architecture ## Architecture
Add a workspace member at `crates/chanora_server_prefetch`. Add a workspace member at `crates/chanora_prefetch`.
Responsibilities: Responsibilities:
@@ -84,7 +84,7 @@ The Flutter bridge keeps calling the same core API, `prefetch_server_resolution(
## Testing ## Testing
Move cache-policy tests from `chanora_core` into `chanora_server_prefetch`: Move cache-policy tests from `chanora_core` into `chanora_prefetch`:
- fresh exact match returns the socket address. - fresh exact match returns the socket address.
- stale entries are ignored. - stale entries are ignored.
@@ -100,7 +100,7 @@ Keep core tests for connection trust-boundary behavior:
Run at minimum: Run at minimum:
- `cargo test -p chanora_server_prefetch --lib` - `cargo test -p chanora_prefetch --lib`
- `cargo test -p chanora_core --lib` - `cargo test -p chanora_core --lib`
- `cargo test -p chanora_protocol --lib` - `cargo test -p chanora_protocol --lib`
@@ -110,7 +110,7 @@ For final confidence, rerun the Android server connect smoke path that verifies
- Workspace builds with the new crate member. - Workspace builds with the new crate member.
- `chanora_core` no longer owns the prefetch cache implementation. - `chanora_core` no longer owns the prefetch cache implementation.
- `chanora_server_prefetch` owns prefetch normalization, TTL, generation, storage, and resolver-backed warming. - `chanora_prefetch` owns prefetch normalization, TTL, generation, storage, and resolver-backed warming.
- Public Flutter and Rust protocol behavior is unchanged. - Public Flutter and Rust protocol behavior is unchanged.
- Existing server connect and reconnect safety tests pass. - Existing server connect and reconnect safety tests pass.
- Android connect still reaches the connected server UI and does not get stuck in `Connecting` or `Synchronizing`. - Android connect still reaches the connected server UI and does not get stuck in `Connecting` or `Synchronizing`.
@@ -18,7 +18,7 @@ This plan defines unit verification coverage for the software modules that imple
| Audio subsystem | `crates/chanora_audio` | DSP, Opus, mixer, gate, PTT logic, baseline examples, benches | Workspace tests and benchmark harnesses; platform loopback evidence is integration/system scope | | Audio subsystem | `crates/chanora_audio` | DSP, Opus, mixer, gate, PTT logic, baseline examples, benches | Workspace tests and benchmark harnesses; platform loopback evidence is integration/system scope |
| Storage | `crates/chanora_storage` | Bookmark repository, identity store, encryption behavior, keyring-disabled CI mode | Workspace tests with `CHANORA_DISABLE_KEYRING=1` in CI | | Storage | `crates/chanora_storage` | Bookmark repository, identity store, encryption behavior, keyring-disabled CI mode | Workspace tests with `CHANORA_DISABLE_KEYRING=1` in CI |
| Diagnostics | `crates/chanora_diagnostics` | Redaction, known-secret registry, diagnostic export JSON, log sink | Workspace tests and security audit plan | | Diagnostics | `crates/chanora_diagnostics` | Redaction, known-secret registry, diagnostic export JSON, log sink | Workspace tests and security audit plan |
| Resolver and prefetch | `crates/chanora_resolver`, `crates/chanora_server_prefetch`, Flutter prefetch debouncer | Resolver fallback, cache TTL, generation safety, debouncer tests | Workspace tests and `apps/chanora_flutter/test/services/prefetch_debouncer_test.dart` | | Resolver and prefetch | `crates/chanora_resolver`, `crates/chanora_prefetch`, Flutter prefetch debouncer | Resolver fallback, cache TTL, generation safety, debouncer tests | Workspace tests and `apps/chanora_flutter/test/services/prefetch_debouncer_test.dart` |
| Flutter services | `apps/chanora_flutter/lib/services` | Dart unit tests | Service tests under `apps/chanora_flutter/test/services/` | | Flutter services | `apps/chanora_flutter/lib/services` | Dart unit tests | Service tests under `apps/chanora_flutter/test/services/` |
| Flutter widgets | `apps/chanora_flutter/lib/widgets` and screen widgets | Widget tests | Widget tests under `apps/chanora_flutter/test/widgets/` | | Flutter widgets | `apps/chanora_flutter/lib/widgets` and screen widgets | Widget tests | Widget tests under `apps/chanora_flutter/test/widgets/` |
@@ -18,7 +18,7 @@ This plan defines how Chanora verifies that independently tested software compon
| Audio to platform | `chanora_audio`, OS audio APIs, Flutter voice controls, platform permissions | SRS-062 through SRS-083, SRS-104 through SRS-115, SRS-135 | Audio loopback tests, platform smoke, mobile device tests | | Audio to platform | `chanora_audio`, OS audio APIs, Flutter voice controls, platform permissions | SRS-062 through SRS-083, SRS-104 through SRS-115, SRS-135 | Audio loopback tests, platform smoke, mobile device tests |
| Storage to platform secure storage | `chanora_storage`, keyring adapters, Flutter bookmark/identity UI | SRS-084 through SRS-095, SRS-126, SRS-137 | Storage tests, platform secure-storage audit | | Storage to platform secure storage | `chanora_storage`, keyring adapters, Flutter bookmark/identity UI | SRS-084 through SRS-095, SRS-126, SRS-137 | Storage tests, platform secure-storage audit |
| Diagnostics export | Diagnostics crate, Flutter diagnostics UI, redaction, share/export surface | SRS-095 through SRS-102, SRS-126, SRS-128 | Redaction tests, diagnostic export review, manual export demo | | Diagnostics export | Diagnostics crate, Flutter diagnostics UI, redaction, share/export surface | SRS-095 through SRS-102, SRS-126, SRS-128 | Redaction tests, diagnostic export review, manual export demo |
| Server resolution prefetch | Flutter host-field debouncer, `chanora_server_prefetch`, `chanora_resolver`, connect path | Resolver/prefetch design specs and connection requirements | Unit tests, Android connect smoke, manual connect demo | | Server resolution prefetch | Flutter host-field debouncer, `chanora_prefetch`, `chanora_resolver`, connect path | Resolver/prefetch design specs and connection requirements | Unit tests, Android connect smoke, manual connect demo |
| Packaging and release build | Flutter build, Rust cdylib/framework/DLL/SO packaging, CI workflows | SRS-116 through SRS-123, SRS-127 | CI build evidence, unsigned iOS build, platform-specific smoke | | Packaging and release build | Flutter build, Rust cdylib/framework/DLL/SO packaging, CI workflows | SRS-116 through SRS-123, SRS-127 | CI build evidence, unsigned iOS build, platform-specific smoke |
## 3. Required Integration Evidence ## 3. Required Integration Evidence