feat(scaffold): create product workspace + Rust crates + Flutter app

Implements the canonical implementation directory layout adopted by
DEC-022 (register v0.9.5). Closes the scaffolding phase; no PoC code
has been promoted in yet (per proof-of-concept-plan.md §4 a PoC is
not product code unless explicitly promoted).

Rust workspace
==============

Top-level Cargo.toml declares seven workspace members:

  core/chanora_core           top-level Rust API + orchestration
  crates/chanora_protocol     tsclientlib isolation (SAD-067, SysDes-011/029)
  crates/chanora_state        state sync, reducers, deltas
  crates/chanora_audio        capture, DSP, Opus, jitter, mixer, playback
  crates/chanora_storage      non-secret DB + platform secure store
  crates/chanora_diagnostics  logs, redaction, export
  crates/chanora_bridge       typed Flutter/Rust DTOs

Workspace-wide pins:
  license      = "MIT OR Apache-2.0"   (DEC-020)
  rust-version = "1.95"
  edition      = "2021"

The Flutter app (apps/chanora_flutter) is NOT a Cargo workspace
member; it is owned by the Flutter / Gradle toolchain and is in the
workspace exclude array along with every poc/* spike.

Each crate ships:
  * a Cargo.toml referring to workspace.dependencies pins;
  * a lib.rs with #![forbid(unsafe_code)] + #![warn(missing_docs)],
    a typed Error enum, and the public types relevant to the
    subsystem's role per SAD §7.2;
  * minimal unit tests so
running 1 test
test tests::defaults_match_decisions ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 1 test
test tests::it_compiles ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 1 test
test tests::session_can_be_constructed ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 1 test
test tests::marker_matches_poc ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 1 test
test tests::it_compiles ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 1 test
test tests::state_transitions_compile ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 1 test
test tests::it_compiles ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s is non-empty.

chanora_core's CoreError type-wraps every subsystem error via
#[from] so callers can match on origin without parsing strings.

chanora_audio's AudioEffects struct defaults all four effects to
true, matching DEC-007 (AEC), DEC-008 (AGC), DEC-009 (NS),
DEC-010 (HPF). A unit test pins this so a future regression that
flips a default fails immediately.

chanora_diagnostics exports REDACTION_MARKER = "[REDACTED]",
identical to the PoC's marker so audit grep patterns survive the
promotion.

chanora_bridge's BridgeError is Serialize + Deserialize so it can
flow across the FRB 2.x boundary (DEC-014).

Empirical verification: cargo check --workspace clean, cargo test
--workspace clean (7 unit tests + 7 doc-test runners, all passing)
against Rust 1.95.0 stable.

Flutter app
===========

apps/chanora_flutter created with .

DEC-004 applied: minSdk overridden to 28 in
android/app/build.gradle.kts with a comment that points back at the
decision register and forbids lowering it without re-opening DEC-004.

DEC-015 applied: shipped English + Simplified Chinese at MVP.
  - pubspec.yaml gains flutter_localizations + intl + generate:true.
  - l10n.yaml emits lib/l10n/generated/AppL10n (no synthetic package
    — that was removed in Flutter 3.41+).
  - lib/l10n/app_en.arb is the source of truth; lib/l10n/app_zh.arb
    mirrors the key set in zh-Hans. ARB metadata explicitly
    reaffirms ADR-008: server-provided content (channel names,
    nicknames, welcome banners) is preserved verbatim and never
    translated.

lib/main.dart and test/widget_test.dart were rewritten from the
template counter into a minimal localized scaffold that proves
both locales render correctly.

Empirical verification:  reports no issues;
 runs the two locale smoke tests and both pass.
This commit is contained in:
EdisonJwa
2026-05-14 21:01:59 +08:00
parent 0f418f1d7e
commit 974dda9601
57 changed files with 2292 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
[package]
name = "chanora_core"
description = "Chanora — top-level Rust API and orchestration. Hosts the connection manager, command dispatcher, and the integration of the protocol, state, audio, storage, and diagnostics subsystems."
version.workspace = true
edition.workspace = true
rust-version.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
publish.workspace = true
[dependencies]
chanora_protocol = { path = "../../crates/chanora_protocol" }
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_bridge = { path = "../../crates/chanora_bridge" }
thiserror.workspace = true
tracing.workspace = true
+96
View File
@@ -0,0 +1,96 @@
//! # `chanora_core`
//!
//! Top-level Rust API and orchestration for the Chanora client.
//!
//! ## Role per SAD §7.2
//!
//! `chanora_core` is the integration point. It owns no protocol,
//! audio, or storage logic directly; instead it composes the
//! subsystem crates ([`chanora_protocol`], [`chanora_state`],
//! [`chanora_audio`], [`chanora_storage`], [`chanora_diagnostics`])
//! behind a stable, typed API consumed by [`chanora_bridge`] (which
//! in turn exposes it to Flutter via `flutter_rust_bridge`, per
//! DEC-014).
//!
//! ## Invariants
//!
//! * Single active server connection at runtime (DEC-006 / SAD-064).
//! * Protocol-specific types from `tsclientlib` do not cross out of
//! [`chanora_protocol`] (SAD-067).
//! * Secret material never lands in [`chanora_storage`]; secrets
//! live in [`chanora_diagnostics`]'s `KnownSecretRegistry` *only*
//! for redaction and in the platform secure-store (DEC-013.2).
//!
//! ## Status
//!
//! This crate is a **scaffold**. No PoC code has been promoted in
//! yet. The public surface below is the integration contract; bodies
//! are placeholders.
#![forbid(unsafe_code)]
#![warn(missing_docs)]
use thiserror::Error;
/// Errors that can arise during top-level orchestration.
///
/// Each arm wraps a typed error from the subsystem that produced it,
/// so callers can match on the originating layer without parsing
/// strings. The variants are intentionally narrow at this stage and
/// will expand as the subsystems land.
#[derive(Debug, Error)]
pub enum CoreError {
/// Protocol-layer error originating from [`chanora_protocol`].
#[error("protocol: {0}")]
Protocol(#[from] chanora_protocol::ProtocolError),
/// State-synchronisation error from [`chanora_state`].
#[error("state: {0}")]
State(#[from] chanora_state::StateError),
/// Audio-subsystem error from [`chanora_audio`].
#[error("audio: {0}")]
Audio(#[from] chanora_audio::AudioError),
/// Storage error from [`chanora_storage`].
#[error("storage: {0}")]
Storage(#[from] chanora_storage::StorageError),
/// Diagnostics error from [`chanora_diagnostics`].
#[error("diagnostics: {0}")]
Diagnostics(#[from] chanora_diagnostics::DiagnosticsError),
/// Bridge / DTO error from [`chanora_bridge`].
#[error("bridge: {0}")]
Bridge(#[from] chanora_bridge::BridgeError),
/// A precondition was violated (typically caller bug or
/// concurrent misuse).
#[error("invariant violated: {0}")]
Invariant(&'static str),
}
/// The top-level Chanora session. Owns exactly one active server
/// connection (DEC-006). Construction does **not** dial the server;
/// see [`ChanoraSession::connect`] (scaffolded only).
pub struct ChanoraSession {
_seal: (),
}
impl ChanoraSession {
/// Construct a new session with the default subsystem
/// configurations. Performs no I/O.
pub fn new() -> Self {
Self { _seal: () }
}
}
impl Default for ChanoraSession {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn session_can_be_constructed() {
let _ = ChanoraSession::new();
}
}